<!doctype html>
<html lang="zh-CN">
<head>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    
    <meta name="referrer" content="no-referrer-when-downgrade">
    

    <title>《Go安全指南》 | 早起的年轻人</title>
    <meta property="og:title" content="《Go安全指南》 - 早起的年轻人">
    <meta property="og:type" content="article">
        
    <meta property="article:published_time" content='2021-01-25T22:44:54&#43;08:00'>
        
        
    <meta property="article:modified_time" content='2021-01-25T22:44:54&#43;08:00'>
        
    <meta name="Keywords" content="Flutter，golang,go语言,go语言笔记,飞雪无情,java,android,博客,项目管理,python,软件架构,公众号,小程序">
    <meta name="description" content="《Go安全指南》">
        
    <meta name="author" content="luckly">
    <meta property="og:url" content="https://luckly.work/post/go/Go%E5%AE%89%E5%85%A8%E6%8C%87%E5%8D%97/">
    <link rel="shortcut icon" href='/favicon.ico'  type="image/x-icon">

    <link rel="stylesheet" href='/css/normalize.css'>
    <link rel="stylesheet" href='/css/style.css'>
    <script type="text/javascript" src="//cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

    
    
    
        <link href="https://cdn.bootcdn.net/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.css" rel="stylesheet">
    
    
    
    
        <link rel="stylesheet" href='/css/douban.css'>
    
        <link rel="stylesheet" href='/css/other.css'>
    
</head>

<link rel="stylesheet"
      href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.2.0/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.2.0/highlight.min.js"></script>
<body>
    <header id="header" class="clearfix">
    <div class="container">
        <div class="col-group">
            <div class="site-name ">
                
                    <a id="logo" href="https://luckly.work/">
                        早起的年轻人
                    </a>
                
                <p class="description">专注于Flutter、Android、Java、Go语言(golang)、移动互联网、项目管理、软件架构</p>
            </div>
            <div>
                <nav id="nav-menu" class="clearfix">
                    <a class="current" href="https://luckly.work/">首页</a>
                    
                    <a  href="https://luckly.work/categories/" title="分类">分类</a>
                    
                    <a  href="https://luckly.work/tags/" title="标签">标签</a>
                    
                    <a  href="https://luckly.work/archives/" title="归档">归档</a>
                    
                    <a  href="https://luckly.work/about/" title="关于我">关于我</a>
                    
                    <a  href="https://github.com/ITmxs/" title="github">github</a>
                    
                </nav>
            </div>
        </div>
    </div>
</header>

    <div id="body">
        <div class="container">
            <div class="col-group">

                <div class="col-8" id="main">
                    
<div class="res-cons">
    <style type="text/css">
    .post-toc {
        position: fixed;
        width: 200px;
        margin-left: -210px;
        padding: 5px 10px;
        font-family: Athelas, STHeiti, Microsoft Yahei, serif;
        font-size: 12px;
        border: 1px solid rgba(0, 0, 0, .07);
        border-radius: 5px;
        background-color: rgba(255, 255, 255, 0.98);
        background-clip: padding-box;
        -webkit-box-shadow: 1px 1px 2px rgba(0, 0, 0, .125);
        box-shadow: 1px 1px 2px rgba(0, 0, 0, .125);
        word-wrap: break-word;
        white-space: nowrap;
        -webkit-box-sizing: border-box;
        box-sizing: border-box;
        z-index: 999;
        cursor: pointer;
        max-height: 70%;
        overflow-y: auto;
        overflow-x: hidden;
    }

    .post-toc .post-toc-title {
        width: 100%;
        margin: 0 auto;
        font-size: 20px;
        font-weight: 400;
        text-transform: uppercase;
        text-align: center;
    }

    .post-toc .post-toc-content {
        font-size: 15px;
    }

    .post-toc .post-toc-content>nav>ul {
        margin: 10px 0;
    }

    .post-toc .post-toc-content ul {
        padding-left: 20px;
        list-style: square;
        margin: 0.5em;
        line-height: 1.8em;
    }

    .post-toc .post-toc-content ul ul {
        padding-left: 15px;
        display: none;
    }

    @media print,
    screen and (max-width:1057px) {
        .post-toc {
            display: none;
        }
    }
</style>
<div class="post-toc" style="position: absolute; top: 188px;">
    <h2 class="post-toc-title">文章目录</h2>
    <div class="post-toc-content">
        <nav id="TableOfContents">
  <ul>
    <li><a href="#1-代码实现类">1. 代码实现类</a>
      <ul>
        <li><a href="#11-内存管理">1.1 内存管理</a></li>
        <li><a href="#12-文件操作">1.2 文件操作</a></li>
        <li><a href="#13-系统接口">1.3 系统接口</a></li>
        <li><a href="#14-通信安全">1.4 通信安全</a></li>
        <li><a href="#15-敏感数据保护">1.5 敏感数据保护</a></li>
        <li><a href="#16-加密解密">1.6 加密解密</a></li>
        <li><a href="#17-正则表达式">1.7 正则表达式</a></li>
      </ul>
    </li>
  </ul>

  <ul>
    <li><a href="#1-代码实现类-1">1 代码实现类</a>
      <ul>
        <li><a href="#11-输入校验">1.1 输入校验</a></li>
        <li><a href="#12-sql操作">1.2 SQL操作</a></li>
        <li><a href="#13-网络请求">1.3 网络请求</a></li>
        <li><a href="#14-服务器端渲染">1.4 服务器端渲染</a></li>
        <li><a href="#15-web跨域">1.5 Web跨域</a></li>
        <li><a href="#16-响应输出">1.6 响应输出</a></li>
        <li><a href="#17-会话管理">1.7 会话管理</a></li>
        <li><a href="#18-访问控制">1.8 访问控制</a></li>
        <li><a href="#19-并发保护">1.9 并发保护</a></li>
      </ul>
    </li>
  </ul>
</nav>
    </div>
</div>
<script type="text/javascript">
    $(document).ready(function () {
        var postToc = $(".post-toc");
        if (postToc.length) {
            var leftPos = $("#main").offset().left;
            if(leftPos<220){
                postToc.css({"width":leftPos-10,"margin-left":(0-leftPos)})
            }

            var t = postToc.offset().top - 20,
                a = {
                    start: {
                        position: "absolute",
                        top: t
                    },
                    process: {
                        position: "fixed",
                        top: 20
                    },
                };
            $(window).scroll(function () {
                var e = $(window).scrollTop();
                e < t ? postToc.css(a.start) : postToc.css(a.process)
            })
        }
    })
</script>
    <article class="post">
        <header>
            <h1 class="post-title">《Go安全指南》</h1>
        </header>
        <date class="post-meta meta-date">
            2021年1月25日
        </date>
        
        <div class="post-meta">
            <span>|</span>
            
            <span class="meta-category"><a href='/categories/go'>go</a></span>
            
        </div>
        
        
        <div class="post-meta">
            <span id="busuanzi_container_page_pv">|<span id="busuanzi_value_page_pv"></span><span>
                    阅读</span></span>
        </div>
        
        
        <div class="clear" style="display: none">
            <div class="toc-article">
                <div class="toc-title">文章目录</div>
            </div>
        </div>
        
        <div class="post-content">
            <blockquote>
<p>本文主要介绍面向开发人员梳理的代码安全指南，旨在梳理API层面的风险点并提供详实可行的安全编码方案。</p>
</blockquote>
<!-- raw HTML omitted -->
<!-- raw HTML omitted -->
<ul>
<li>
<p><a href="#1">1 通用类</a></p>
<ul>
<li><a href="#1.1">I. 代码实现</a>
<ul>
<li><a href="#1.1.1">1.1 内存管理</a></li>
<li><a href="#1.1.2">1.2 文件操作</a></li>
<li><a href="#1.1.3">1.3 系统接口</a></li>
<li><a href="#1.1.4">1.4 通信安全</a></li>
<li><a href="#1.1.5">1.5 敏感数据保护</a></li>
<li><a href="#1.1.6">1.6 加密解密</a></li>
<li><a href="#1.1.7">1.7 正则表达式</a></li>
</ul>
</li>
</ul>
</li>
<li>
<p><a href="#2">2 后台类</a></p>
<ul>
<li><a href="#2.1">I. 代码实现</a>
<ul>
<li><a href="#2.1.1">1.1 输入校验</a></li>
<li><a href="#2.1.2">1.2 SQL操作</a></li>
<li><a href="#2.1.3">1.3 网络请求</a></li>
<li><a href="#2.1.4">1.4 服务器端渲染</a></li>
<li><a href="#2.1.5">1.5 Web跨域</a></li>
<li><a href="#2.1.6">1.6 响应输出</a></li>
<li><a href="#2.1.7">1.7 会话管理</a></li>
<li><a href="#2.1.8">1.8 访问控制</a></li>
<li><a href="#2.1.9">1.9 并发保护</a>
<!-- raw HTML omitted -->
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h1 id="通用类">通用类</h1>
<p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h2 id="1-代码实现类">1. 代码实现类</h2>
<p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h3 id="11-内存管理">1.1 内存管理</h3>
<h4 id="111必须切片长度校验">1.1.1【必须】切片长度校验</h4>
<ul>
<li>在对slice进行操作时，必须判断长度是否合法，防止程序panic</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// bad: 未判断data的长度，可导致 index out of range 
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">decode</span>(<span style="color:#a6e22e">data</span> [] <span style="color:#66d9ef">byte</span>) <span style="color:#66d9ef">bool</span> {
    <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">data</span>[<span style="color:#ae81ff">0</span>] <span style="color:#f92672">==</span> <span style="color:#e6db74">&#39;F&#39;</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">data</span>[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">==</span> <span style="color:#e6db74">&#39;U&#39;</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">data</span>[<span style="color:#ae81ff">2</span>] <span style="color:#f92672">==</span> <span style="color:#e6db74">&#39;Z&#39;</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">data</span>[<span style="color:#ae81ff">3</span>] <span style="color:#f92672">==</span> <span style="color:#e6db74">&#39;Z&#39;</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">data</span>[<span style="color:#ae81ff">4</span>] <span style="color:#f92672">==</span> <span style="color:#e6db74">&#39;E&#39;</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">data</span>[<span style="color:#ae81ff">5</span>] <span style="color:#f92672">==</span> <span style="color:#e6db74">&#39;R&#39;</span> {
        <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Bad&#34;</span>)
        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>
    }
  
    <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>
}

<span style="color:#75715e">// bad: slice bounds out of range
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">foo</span>() {
    <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">slice</span> = []<span style="color:#66d9ef">int</span>{<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">4</span>, <span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">6</span>}
    <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">slice</span>[:<span style="color:#ae81ff">10</span>]) 
}

<span style="color:#75715e">// good: 使用data前应判断长度是否合法 
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">decode</span>(<span style="color:#a6e22e">data</span> [] <span style="color:#66d9ef">byte</span>) <span style="color:#66d9ef">bool</span> {
    <span style="color:#66d9ef">if</span> len(<span style="color:#a6e22e">data</span>) <span style="color:#f92672">==</span> <span style="color:#ae81ff">6</span> {
        <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">data</span>[<span style="color:#ae81ff">0</span>] <span style="color:#f92672">==</span> <span style="color:#e6db74">&#39;F&#39;</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">data</span>[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">==</span> <span style="color:#e6db74">&#39;U&#39;</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">data</span>[<span style="color:#ae81ff">2</span>] <span style="color:#f92672">==</span> <span style="color:#e6db74">&#39;Z&#39;</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">data</span>[<span style="color:#ae81ff">3</span>] <span style="color:#f92672">==</span> <span style="color:#e6db74">&#39;Z&#39;</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">data</span>[<span style="color:#ae81ff">4</span>] <span style="color:#f92672">==</span> <span style="color:#e6db74">&#39;E&#39;</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">data</span>[<span style="color:#ae81ff">5</span>] <span style="color:#f92672">==</span> <span style="color:#e6db74">&#39;R&#39;</span> {
            <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Good&#34;</span>)
            <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>
        }
    }
	
    <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>
}
</code></pre></div><h4 id="112必须nil指针判断">1.1.2【必须】nil指针判断</h4>
<ul>
<li>进行指针操作时，必须判断该指针是否为nil，防止程序panic，尤其在进行结构体Unmarshal时</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Packet</span> <span style="color:#66d9ef">struct</span> {
    <span style="color:#a6e22e">PackeyType</span>        <span style="color:#66d9ef">uint8</span>
    <span style="color:#a6e22e">PackeyVersion</span>     <span style="color:#66d9ef">uint8</span>
    <span style="color:#a6e22e">Data</span>              <span style="color:#f92672">*</span><span style="color:#a6e22e">Data</span>
}

<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Data</span> <span style="color:#66d9ef">struct</span> {
    <span style="color:#a6e22e">Stat</span>    <span style="color:#66d9ef">uint8</span>
    <span style="color:#a6e22e">Len</span> 	<span style="color:#66d9ef">uint8</span>
    <span style="color:#a6e22e">Buf</span> 	[<span style="color:#ae81ff">8</span>]<span style="color:#66d9ef">byte</span>
}

<span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">p</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Packet</span>) <span style="color:#a6e22e">UnmarshalBinary</span>(<span style="color:#a6e22e">b</span> []<span style="color:#66d9ef">byte</span>) <span style="color:#66d9ef">error</span> {
    <span style="color:#66d9ef">if</span> len(<span style="color:#a6e22e">b</span>) &lt; <span style="color:#ae81ff">2</span> {
       <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">io</span>.<span style="color:#a6e22e">EOF</span>
    }
  
    <span style="color:#a6e22e">p</span>.<span style="color:#a6e22e">PackeyType</span> = <span style="color:#a6e22e">b</span>[<span style="color:#ae81ff">0</span>]
    <span style="color:#a6e22e">p</span>.<span style="color:#a6e22e">PackeyVersion</span> = <span style="color:#a6e22e">b</span>[<span style="color:#ae81ff">1</span>]
  
    <span style="color:#75715e">// 若长度等于2，那么不会new Data
</span><span style="color:#75715e"></span>    <span style="color:#66d9ef">if</span> len(<span style="color:#a6e22e">b</span>) &gt; <span style="color:#ae81ff">2</span> {
        <span style="color:#a6e22e">p</span>.<span style="color:#a6e22e">Data</span> = new(<span style="color:#a6e22e">Data</span>)
        <span style="color:#75715e">// Unmarshal(b[i:], p.Data)
</span><span style="color:#75715e"></span>    }
  
    <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
}

<span style="color:#75715e">// bad: 未判断指针是否为nil
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
    <span style="color:#a6e22e">packet</span> <span style="color:#f92672">:=</span> new(<span style="color:#a6e22e">Packet</span>)
    <span style="color:#a6e22e">data</span> <span style="color:#f92672">:=</span> make([]<span style="color:#66d9ef">byte</span>, <span style="color:#ae81ff">2</span>)
    <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">packet</span>.<span style="color:#a6e22e">UnmarshalBinary</span>(<span style="color:#a6e22e">data</span>); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
        <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Failed to unmarshal packet&#34;</span>)
        <span style="color:#66d9ef">return</span>
    }
    
    <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;Stat: %v\n&#34;</span>, <span style="color:#a6e22e">packet</span>.<span style="color:#a6e22e">Data</span>.<span style="color:#a6e22e">Stat</span>)
}

<span style="color:#75715e">// good: 判断Data指针是否未nil
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
    
    <span style="color:#a6e22e">packet</span> <span style="color:#f92672">:=</span> new(<span style="color:#a6e22e">Packet</span>)
    <span style="color:#a6e22e">data</span> <span style="color:#f92672">:=</span> make([]<span style="color:#66d9ef">byte</span>, <span style="color:#ae81ff">2</span>)
    
    <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">packet</span>.<span style="color:#a6e22e">UnmarshalBinary</span>(<span style="color:#a6e22e">data</span>); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
        <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Failed to unmarshal packet&#34;</span>)
        <span style="color:#66d9ef">return</span>
    }
    
    <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">packet</span>.<span style="color:#a6e22e">Data</span> <span style="color:#f92672">==</span> <span style="color:#66d9ef">nil</span> {
        <span style="color:#66d9ef">return</span>
    }
    
    <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;Stat: %v\n&#34;</span>, <span style="color:#a6e22e">packet</span>.<span style="color:#a6e22e">Data</span>.<span style="color:#a6e22e">Stat</span>)
}
</code></pre></div><h4 id="113必须整数安全">1.1.3【必须】整数安全</h4>
<ul>
<li>
<p>在进行数字运算操作时，需要做好长度限制，防止外部输入运算导致异常：</p>
<ul>
<li>确保无符号整数运算时不会反转</li>
<li>确保有符号整数运算时不会出现溢出</li>
<li>确保整型转换时不会出现截断错误</li>
<li>确保整型转换时不会出现符号错误</li>
</ul>
</li>
<li>
<p>以下场景必须严格进行长度限制：</p>
<ul>
<li>作为数组索引</li>
<li>作为对象的长度或者大小</li>
<li>作为数组的边界(如作为循环计数器)</li>
</ul>
</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// bad: 未限制长度，导致整数溢出
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">overflow</span>(<span style="color:#a6e22e">numControlByUser</span> <span style="color:#66d9ef">int32</span>) {
    <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">numInt</span> <span style="color:#66d9ef">int32</span> = <span style="color:#ae81ff">0</span>
    <span style="color:#a6e22e">numInt</span> = <span style="color:#a6e22e">numControlByUser</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>
    <span style="color:#75715e">//对长度限制不当，导致整数溢出
</span><span style="color:#75715e"></span>    <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;%d\n&#34;</span>, <span style="color:#a6e22e">numInt</span>)
    <span style="color:#75715e">//使用numInt，可能导致其他错误
</span><span style="color:#75715e"></span>}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
    <span style="color:#a6e22e">overflow</span>(<span style="color:#ae81ff">2147483647</span>)
}

<span style="color:#75715e">// good: 
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">overflow</span>(<span style="color:#a6e22e">numControlByUser</span> <span style="color:#66d9ef">int32</span>) {
    <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">numInt</span> <span style="color:#66d9ef">int32</span> = <span style="color:#ae81ff">0</span>
    <span style="color:#a6e22e">numInt</span> = <span style="color:#a6e22e">numControlByUser</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>
    <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">numInt</span> &lt; <span style="color:#ae81ff">0</span> {
        <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;integer overflow&#34;</span>)
        <span style="color:#66d9ef">return</span>;
    } 
    <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;integer ok&#34;</span>)
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
    <span style="color:#a6e22e">overflow</span>(<span style="color:#ae81ff">2147483647</span>)
}
</code></pre></div><h4 id="114必须make分配长度验证">1.1.4【必须】make分配长度验证</h4>
<ul>
<li>在进行make分配内存时，需要对外部可控的长度进行校验，防止程序panic。</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// bad
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">parse</span>(<span style="color:#a6e22e">lenControlByUser</span> <span style="color:#66d9ef">int</span>, <span style="color:#a6e22e">data</span>[] <span style="color:#66d9ef">byte</span>) {
    <span style="color:#a6e22e">size</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">lenControlByUser</span>
    <span style="color:#75715e">//对外部传入的size，进行长度判断以免导致panic
</span><span style="color:#75715e"></span>    <span style="color:#a6e22e">buffer</span> <span style="color:#f92672">:=</span> make([]<span style="color:#66d9ef">byte</span>, <span style="color:#a6e22e">size</span>)
    copy(<span style="color:#a6e22e">buffer</span>, <span style="color:#a6e22e">data</span>)
}

<span style="color:#75715e">// good
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">parse</span>(<span style="color:#a6e22e">lenControlByUser</span> <span style="color:#66d9ef">int</span>, <span style="color:#a6e22e">data</span>[] <span style="color:#66d9ef">byte</span>) ([]<span style="color:#66d9ef">byte</span>, <span style="color:#66d9ef">error</span>){
    <span style="color:#a6e22e">size</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">lenControlByUser</span>
    <span style="color:#75715e">//限制外部可控的长度大小范围
</span><span style="color:#75715e"></span>    <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">size</span> &gt; <span style="color:#ae81ff">64</span><span style="color:#f92672">*</span><span style="color:#ae81ff">1024</span><span style="color:#f92672">*</span><span style="color:#ae81ff">1024</span> {
        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">errors</span>.<span style="color:#a6e22e">New</span>(<span style="color:#e6db74">&#34;value too large&#34;</span>)
    }
    <span style="color:#a6e22e">buffer</span> <span style="color:#f92672">:=</span> make([]<span style="color:#66d9ef">byte</span>, <span style="color:#a6e22e">size</span>)
    copy(<span style="color:#a6e22e">buffer</span>, <span style="color:#a6e22e">data</span>)
    <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">buffer</span>, <span style="color:#66d9ef">nil</span>
}
</code></pre></div><h4 id="115必须禁止setfinalizer和指针循环引用同时使用">1.1.5【必须】禁止SetFinalizer和指针循环引用同时使用</h4>
<ul>
<li>当一个对象从被GC选中到移除内存之前，runtime.SetFinalizer()都不会执行，即使程序正常结束或者发生错误。由指针构成的“循环引用”虽然能被GC正确处理，但由于无法确定Finalizer依赖顺序，从而无法调用runtime.SetFinalizer()，导致目标对象无法变成可达状态，从而造成内存无法被回收。</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// bad
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">foo</span>() {
    <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">a</span>, <span style="color:#a6e22e">b</span> <span style="color:#a6e22e">Data</span>
    <span style="color:#a6e22e">a</span>.<span style="color:#a6e22e">o</span> = <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">b</span>
    <span style="color:#a6e22e">b</span>.<span style="color:#a6e22e">o</span> = <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">a</span>

    <span style="color:#75715e">//指针循环引用，SetFinalizer()无法正常调用
</span><span style="color:#75715e"></span>    <span style="color:#a6e22e">runtime</span>.<span style="color:#a6e22e">SetFinalizer</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">a</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">d</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Data</span>) {
        <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;a %p final.\n&#34;</span>, <span style="color:#a6e22e">d</span>)
    })
    <span style="color:#a6e22e">runtime</span>.<span style="color:#a6e22e">SetFinalizer</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">b</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">d</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Data</span>) {
        <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;b %p final.\n&#34;</span>, <span style="color:#a6e22e">d</span>)
    })
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
    <span style="color:#66d9ef">for</span> {
        <span style="color:#a6e22e">foo</span>()
        <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Sleep</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Millisecond</span>)
    }
}
</code></pre></div><h4 id="116必须禁止重复释放channel">1.1.6【必须】禁止重复释放channel</h4>
<ul>
<li>重复释放一般存在于异常流程判断中，如果恶意攻击者构造出异常条件使程序重复释放channel，则会触发运行时恐慌，从而造成DoS攻击。</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// bad
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">foo</span>(<span style="color:#a6e22e">c</span> <span style="color:#66d9ef">chan</span> <span style="color:#66d9ef">int</span>) {
    <span style="color:#66d9ef">defer</span> close(<span style="color:#a6e22e">c</span>)
    <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">processBusiness</span>()
    <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
        <span style="color:#a6e22e">c</span> <span style="color:#f92672">&lt;-</span> <span style="color:#ae81ff">0</span>
        close(<span style="color:#a6e22e">c</span>) <span style="color:#75715e">// 重复释放channel
</span><span style="color:#75715e"></span>        <span style="color:#66d9ef">return</span>
    }
    <span style="color:#a6e22e">c</span> <span style="color:#f92672">&lt;-</span> <span style="color:#ae81ff">1</span>
}

<span style="color:#75715e">// good
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">foo</span>(<span style="color:#a6e22e">c</span> <span style="color:#66d9ef">chan</span> <span style="color:#66d9ef">int</span>) {
    <span style="color:#66d9ef">defer</span> close(<span style="color:#a6e22e">c</span>) <span style="color:#75715e">// 使用defer延迟关闭channel
</span><span style="color:#75715e"></span>    <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">processBusiness</span>()
    <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
        <span style="color:#a6e22e">c</span> <span style="color:#f92672">&lt;-</span> <span style="color:#ae81ff">0</span>
        <span style="color:#66d9ef">return</span>
    }
    <span style="color:#a6e22e">c</span> <span style="color:#f92672">&lt;-</span> <span style="color:#ae81ff">1</span>
}
</code></pre></div><h4 id="117必须确保每个协程都能退出">1.1.7【必须】确保每个协程都能退出</h4>
<ul>
<li>启动一个协程就会做一个入栈操作，在系统不退出的情况下，协程也没有设置退出条件，则相当于协程失去了控制，它占用的资源无法回收，可能会导致内存泄露。</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// bad: 协程没有设置退出条件
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">doWaiter</span>(<span style="color:#a6e22e">name</span> <span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">second</span> <span style="color:#66d9ef">int</span>) {
    <span style="color:#66d9ef">for</span> {
        <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Sleep</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Duration</span>(<span style="color:#a6e22e">second</span>) <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Second</span>)
        <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">name</span>, <span style="color:#e6db74">&#34; is ready!&#34;</span>)
    }
}
</code></pre></div><h4 id="118推荐不使用unsafe包">1.1.8【推荐】不使用unsafe包</h4>
<ul>
<li>由于unsafe包绕过了 Golang 的内存安全原则，一般来说使用该库是不安全的，可导致内存破坏，尽量避免使用该包。若必须要使用unsafe操作指针，必须做好安全校验。</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// bad: 通过unsafe操作原始指针
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">unsafePointer</span>() {
    <span style="color:#a6e22e">b</span> <span style="color:#f92672">:=</span> make([]<span style="color:#66d9ef">byte</span>, <span style="color:#ae81ff">1</span>)
    <span style="color:#a6e22e">foo</span> <span style="color:#f92672">:=</span> (<span style="color:#f92672">*</span><span style="color:#66d9ef">int</span>)(<span style="color:#a6e22e">unsafe</span>.<span style="color:#a6e22e">Pointer</span>(uintptr(<span style="color:#a6e22e">unsafe</span>.<span style="color:#a6e22e">Pointer</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">b</span>[<span style="color:#ae81ff">0</span>])) <span style="color:#f92672">+</span> uintptr(<span style="color:#ae81ff">0xfffffffe</span>)))
    <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Print</span>(<span style="color:#f92672">*</span><span style="color:#a6e22e">foo</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>)
}

<span style="color:#75715e">// [signal SIGSEGV: segmentation violation code=0x1 addr=0xc100068f55 pc=0x49142b]
</span></code></pre></div><h4 id="119推荐不使用slice作为函数入参">1.1.9【推荐】不使用slice作为函数入参</h4>
<ul>
<li>slice是引用类型，在作为函数入参时采用的是地址传递，对slice的修改也会影响原始数据</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go">  <span style="color:#75715e">// bad
</span><span style="color:#75715e"></span>  <span style="color:#75715e">// slice作为函数入参时是地址传递
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">modify</span>(<span style="color:#a6e22e">array</span> []<span style="color:#66d9ef">int</span>) {
      <span style="color:#a6e22e">array</span>[<span style="color:#ae81ff">0</span>] = <span style="color:#ae81ff">10</span> <span style="color:#75715e">// 对入参slice的元素修改会影响原始数据
</span><span style="color:#75715e"></span>  }
  
  <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
      <span style="color:#a6e22e">array</span> <span style="color:#f92672">:=</span> []<span style="color:#66d9ef">int</span>{<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">4</span>, <span style="color:#ae81ff">5</span>}
  
      <span style="color:#a6e22e">modify</span>(<span style="color:#a6e22e">array</span>)
      <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">array</span>) <span style="color:#75715e">// output：[10 2 3 4 5]
</span><span style="color:#75715e"></span>  }

  <span style="color:#75715e">// good
</span><span style="color:#75715e"></span>  <span style="color:#75715e">// 数组作为函数入参时，而不是slice
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">modify</span>(<span style="color:#a6e22e">array</span> [<span style="color:#ae81ff">5</span>]<span style="color:#66d9ef">int</span>) {
    <span style="color:#a6e22e">array</span>[<span style="color:#ae81ff">0</span>] = <span style="color:#ae81ff">10</span>
  }

  <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
      <span style="color:#75715e">// 传入数组，注意数组与slice的区别
</span><span style="color:#75715e"></span>      <span style="color:#a6e22e">array</span> <span style="color:#f92672">:=</span> [<span style="color:#ae81ff">5</span>]<span style="color:#66d9ef">int</span>{<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">4</span>, <span style="color:#ae81ff">5</span>}
  
      <span style="color:#a6e22e">modify</span>(<span style="color:#a6e22e">array</span>)
      <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">array</span>)
  }
</code></pre></div><p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h3 id="12-文件操作">1.2 文件操作</h3>
<h4 id="121必须-路径穿越检查">1.2.1【必须】 路径穿越检查</h4>
<ul>
<li>在进行文件操作时，如果对外部传入的文件名未做限制，可能导致任意文件读取或者任意文件写入，严重可能导致代码执行。</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// bad: 任意文件读取
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">handler</span>(<span style="color:#a6e22e">w</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ResponseWriter</span>, <span style="color:#a6e22e">r</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) {
	<span style="color:#a6e22e">path</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">URL</span>.<span style="color:#a6e22e">Query</span>()[<span style="color:#e6db74">&#34;path&#34;</span>][<span style="color:#ae81ff">0</span>]

	<span style="color:#75715e">// 未过滤文件路径，可能导致任意文件读取
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">data</span>, <span style="color:#a6e22e">_</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">ioutil</span>.<span style="color:#a6e22e">ReadFile</span>(<span style="color:#a6e22e">path</span>)
	<span style="color:#a6e22e">w</span>.<span style="color:#a6e22e">Write</span>(<span style="color:#a6e22e">data</span>)

	<span style="color:#75715e">// 对外部传入的文件名变量，还需要验证是否存在../等路径穿越的文件名
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">data</span>, <span style="color:#a6e22e">_</span> = <span style="color:#a6e22e">ioutil</span>.<span style="color:#a6e22e">ReadFile</span>(<span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#e6db74">&#34;/home/user/&#34;</span>, <span style="color:#a6e22e">path</span>))
	<span style="color:#a6e22e">w</span>.<span style="color:#a6e22e">Write</span>(<span style="color:#a6e22e">data</span>)
}

<span style="color:#75715e">// bad: 任意文件写入
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">unzip</span>(<span style="color:#a6e22e">f</span> <span style="color:#66d9ef">string</span>) {
	<span style="color:#a6e22e">r</span>, <span style="color:#a6e22e">_</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">zip</span>.<span style="color:#a6e22e">OpenReader</span>(<span style="color:#a6e22e">f</span>)
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">f</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">File</span> {
		<span style="color:#a6e22e">p</span>, <span style="color:#a6e22e">_</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Abs</span>(<span style="color:#a6e22e">f</span>.<span style="color:#a6e22e">Name</span>)
		<span style="color:#75715e">// 未验证压缩文件名，可能导致../等路径穿越，任意文件路径写入
</span><span style="color:#75715e"></span>		<span style="color:#a6e22e">ioutil</span>.<span style="color:#a6e22e">WriteFile</span>(<span style="color:#a6e22e">p</span>, []byte(<span style="color:#e6db74">&#34;present&#34;</span>), <span style="color:#ae81ff">0640</span>)
	}
}

<span style="color:#75715e">// good: 检查压缩的文件名是否包含..路径穿越特征字符，防止任意写入
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">unzipGood</span>(<span style="color:#a6e22e">f</span> <span style="color:#66d9ef">string</span>) <span style="color:#66d9ef">bool</span> {
	<span style="color:#a6e22e">r</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">zip</span>.<span style="color:#a6e22e">OpenReader</span>(<span style="color:#a6e22e">f</span>)
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;read zip file fail&#34;</span>)
		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>
	}
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">f</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">File</span> {
		<span style="color:#a6e22e">p</span>, <span style="color:#a6e22e">_</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Abs</span>(<span style="color:#a6e22e">f</span>.<span style="color:#a6e22e">Name</span>)
		<span style="color:#66d9ef">if</span> !<span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Contains</span>(<span style="color:#a6e22e">p</span>, <span style="color:#e6db74">&#34;..&#34;</span>) {
			<span style="color:#a6e22e">ioutil</span>.<span style="color:#a6e22e">WriteFile</span>(<span style="color:#a6e22e">p</span>, []byte(<span style="color:#e6db74">&#34;present&#34;</span>), <span style="color:#ae81ff">0640</span>)
		}
	}
	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>
}
</code></pre></div><h4 id="122必须-文件访问权限">1.2.2【必须】 文件访问权限</h4>
<ul>
<li>根据创建文件的敏感性设置不同级别的访问权限，以防止敏感数据被任意权限用户读取。例如，设置文件权限为：<code>-rw-r-----</code></li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#a6e22e">ioutil</span>.<span style="color:#a6e22e">WriteFile</span>(<span style="color:#a6e22e">p</span>, []byte(<span style="color:#e6db74">&#34;present&#34;</span>), <span style="color:#ae81ff">0640</span>)
</code></pre></div><p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h3 id="13-系统接口">1.3 系统接口</h3>
<p><strong>1.3.1【必须】命令执行检查</strong></p>
<ul>
<li>使用<code>exec.Command</code>、<code>exec.CommandContext</code>、<code>syscall.StartProcess</code>、<code>os.StartProcess</code>等函数时，第一个参数(path)直接取外部输入值时，应使用白名单限定可执行的命令范围，不允许传入<code>bash</code>、<code>cmd</code>、<code>sh</code>等命令；</li>
<li>使用<code>exec.Command</code>、<code>exec.CommandContext</code>等函数时，通过<code>bash</code>、<code>cmd</code>、<code>sh</code>等创建shell，-c后的参数(arg)拼接外部输入，应过滤\n  $  &amp;  ;  |  '  &quot;  ( )  `等潜在恶意字符；</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// bad
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">foo</span>() {
	<span style="color:#a6e22e">userInputedVal</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;&amp;&amp; echo &#39;hello&#39;&#34;</span> <span style="color:#75715e">// 假设外部传入该变量值
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">cmdName</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;ping &#34;</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">userInputedVal</span>

	<span style="color:#75715e">//未判断外部输入是否存在命令注入字符，结合sh可造成命令注入
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#e6db74">&#34;sh&#34;</span>, <span style="color:#e6db74">&#34;-c&#34;</span>, <span style="color:#a6e22e">cmdName</span>)
	<span style="color:#a6e22e">output</span>, <span style="color:#a6e22e">_</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>()
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(string(<span style="color:#a6e22e">output</span>))

	<span style="color:#a6e22e">cmdName</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;ls&#34;</span>
	<span style="color:#75715e">//未判断外部输入是否是预期命令
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdName</span>)
	<span style="color:#a6e22e">output</span>, <span style="color:#a6e22e">_</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>()
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(string(<span style="color:#a6e22e">output</span>))
}

<span style="color:#75715e">// good
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">checkIllegal</span>(<span style="color:#a6e22e">cmdName</span> <span style="color:#66d9ef">string</span>) <span style="color:#66d9ef">bool</span> {
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Contains</span>(<span style="color:#a6e22e">cmdName</span>, <span style="color:#e6db74">&#34;&amp;&#34;</span>) <span style="color:#f92672">||</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Contains</span>(<span style="color:#a6e22e">cmdName</span>, <span style="color:#e6db74">&#34;|&#34;</span>) <span style="color:#f92672">||</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Contains</span>(<span style="color:#a6e22e">cmdName</span>, <span style="color:#e6db74">&#34;;&#34;</span>) <span style="color:#f92672">||</span>
		<span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Contains</span>(<span style="color:#a6e22e">cmdName</span>, <span style="color:#e6db74">&#34;$&#34;</span>) <span style="color:#f92672">||</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Contains</span>(<span style="color:#a6e22e">cmdName</span>, <span style="color:#e6db74">&#34;&#39;&#34;</span>) <span style="color:#f92672">||</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Contains</span>(<span style="color:#a6e22e">cmdName</span>, <span style="color:#e6db74">&#34;`&#34;</span>) <span style="color:#f92672">||</span>
		<span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Contains</span>(<span style="color:#a6e22e">cmdName</span>, <span style="color:#e6db74">&#34;(&#34;</span>) <span style="color:#f92672">||</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Contains</span>(<span style="color:#a6e22e">cmdName</span>, <span style="color:#e6db74">&#34;)&#34;</span>) <span style="color:#f92672">||</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Contains</span>(<span style="color:#a6e22e">cmdName</span>, <span style="color:#e6db74">&#34;\&#34;&#34;</span>) {
		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>
	}
	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">userInputedVal</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;&amp;&amp; echo &#39;hello&#39;&#34;</span>
	<span style="color:#a6e22e">cmdName</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;ping &#34;</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">userInputedVal</span>

	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">checkIllegal</span>(<span style="color:#a6e22e">cmdName</span>) { <span style="color:#75715e">// 检查传给sh的命令是否有特殊字符
</span><span style="color:#75715e"></span>		<span style="color:#66d9ef">return</span> <span style="color:#75715e">// 存在特殊字符直接return
</span><span style="color:#75715e"></span>	}

	<span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#e6db74">&#34;sh&#34;</span>, <span style="color:#e6db74">&#34;-c&#34;</span>, <span style="color:#a6e22e">cmdName</span>)
	<span style="color:#a6e22e">output</span>, <span style="color:#a6e22e">_</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>()
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(string(<span style="color:#a6e22e">output</span>))
}
</code></pre></div><p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h3 id="14-通信安全">1.4 通信安全</h3>
<h4 id="141必须网络通信采用tls方式">1.4.1【必须】网络通信采用TLS方式</h4>
<ul>
<li>明文传输的通信协议目前已被验证存在较大安全风险，被中间人劫持后可能导致许多安全风险，因此必须采用至少TLS的安全通信方式保证通信安全，例如gRPC/Websocket都使用TLS1.3。</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// good
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
  <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">HandleFunc</span>(<span style="color:#e6db74">&#34;/&#34;</span>, <span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">w</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ResponseWriter</span>, <span style="color:#a6e22e">req</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) {
    <span style="color:#a6e22e">w</span>.<span style="color:#a6e22e">Header</span>().<span style="color:#a6e22e">Add</span>(<span style="color:#e6db74">&#34;Strict-Transport-Security&#34;</span>, <span style="color:#e6db74">&#34;max-age=63072000; includeSubDomains&#34;</span>)
    <span style="color:#a6e22e">w</span>.<span style="color:#a6e22e">Write</span>([]byte(<span style="color:#e6db74">&#34;This is an example server.\n&#34;</span>))
  })

  <span style="color:#75715e">//服务器配置证书与私钥
</span><span style="color:#75715e"></span>  <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ListenAndServeTLS</span>(<span style="color:#e6db74">&#34;:443&#34;</span>, <span style="color:#e6db74">&#34;yourCert.pem&#34;</span>, <span style="color:#e6db74">&#34;yourKey.pem&#34;</span>, <span style="color:#66d9ef">nil</span>))
}
</code></pre></div><h4 id="142推荐tls启用证书验证">1.4.2【推荐】TLS启用证书验证</h4>
<ul>
<li>TLS证书应当是有效的、未过期的，且配置正确的域名，生产环境的服务端应启用证书验证。</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// bad
</span><span style="color:#75715e"></span><span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;crypto/tls&#34;</span>
	<span style="color:#e6db74">&#34;net/http&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">doAuthReq</span>(<span style="color:#a6e22e">authReq</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Response</span> {
	<span style="color:#a6e22e">tr</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Transport</span>{
		<span style="color:#a6e22e">TLSClientConfig</span>: <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">tls</span>.<span style="color:#a6e22e">Config</span>{<span style="color:#a6e22e">InsecureSkipVerify</span>: <span style="color:#66d9ef">true</span>},
	}
	<span style="color:#a6e22e">client</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Client</span>{<span style="color:#a6e22e">Transport</span>: <span style="color:#a6e22e">tr</span>}
	<span style="color:#a6e22e">res</span>, <span style="color:#a6e22e">_</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">client</span>.<span style="color:#a6e22e">Do</span>(<span style="color:#a6e22e">authReq</span>)
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">res</span>
}

<span style="color:#75715e">// good
</span><span style="color:#75715e"></span><span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;crypto/tls&#34;</span>
	<span style="color:#e6db74">&#34;net/http&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">doAuthReq</span>(<span style="color:#a6e22e">authReq</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Response</span> {
	<span style="color:#a6e22e">tr</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Transport</span>{
		<span style="color:#a6e22e">TLSClientConfig</span>: <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">tls</span>.<span style="color:#a6e22e">Config</span>{<span style="color:#a6e22e">InsecureSkipVerify</span>: <span style="color:#66d9ef">false</span>},
	}
	<span style="color:#a6e22e">client</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Client</span>{<span style="color:#a6e22e">Transport</span>: <span style="color:#a6e22e">tr</span>}
	<span style="color:#a6e22e">res</span>, <span style="color:#a6e22e">_</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">client</span>.<span style="color:#a6e22e">Do</span>(<span style="color:#a6e22e">authReq</span>)
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">res</span>
}
</code></pre></div><p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h3 id="15-敏感数据保护">1.5 敏感数据保护</h3>
<h4 id="151必须敏感信息访问">1.5.1【必须】敏感信息访问</h4>
<ul>
<li>禁止将敏感信息硬编码在程序中，既可能会将敏感信息暴露给攻击者，也会增加代码管理和维护的难度</li>
<li>使用配置中心系统统一托管密钥等敏感信息</li>
</ul>
<h4 id="152必须敏感数据输出">1.5.2【必须】敏感数据输出</h4>
<ul>
<li>只输出必要的最小数据集，避免多余字段暴露引起敏感信息泄露</li>
<li>不能在日志保存密码(包括明文密码和密文密码)、密钥和其它敏感信息</li>
<li>对于必须输出的敏感信息，必须进行合理脱敏展示</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// bad
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">serve</span>() {
	<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">HandleFunc</span>(<span style="color:#e6db74">&#34;/register&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">w</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ResponseWriter</span>, <span style="color:#a6e22e">r</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) {
		<span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">ParseForm</span>()
		<span style="color:#a6e22e">user</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">Form</span>.<span style="color:#a6e22e">Get</span>(<span style="color:#e6db74">&#34;user&#34;</span>)
		<span style="color:#a6e22e">pw</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">Form</span>.<span style="color:#a6e22e">Get</span>(<span style="color:#e6db74">&#34;password&#34;</span>)

		<span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;Registering new user %s with password %s.\n&#34;</span>, <span style="color:#a6e22e">user</span>, <span style="color:#a6e22e">pw</span>)
	})
	<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ListenAndServe</span>(<span style="color:#e6db74">&#34;:80&#34;</span>, <span style="color:#66d9ef">nil</span>)
}

<span style="color:#75715e">// good
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">serve1</span>() {
	<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">HandleFunc</span>(<span style="color:#e6db74">&#34;/register&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">w</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ResponseWriter</span>, <span style="color:#a6e22e">r</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) {
		<span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">ParseForm</span>()
		<span style="color:#a6e22e">user</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">Form</span>.<span style="color:#a6e22e">Get</span>(<span style="color:#e6db74">&#34;user&#34;</span>)
		<span style="color:#a6e22e">pw</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">Form</span>.<span style="color:#a6e22e">Get</span>(<span style="color:#e6db74">&#34;password&#34;</span>)

		<span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;Registering new user %s.\n&#34;</span>, <span style="color:#a6e22e">user</span>)

		<span style="color:#75715e">// ...
</span><span style="color:#75715e"></span>		<span style="color:#a6e22e">use</span>(<span style="color:#a6e22e">pw</span>)
	})
	<span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ListenAndServe</span>(<span style="color:#e6db74">&#34;:80&#34;</span>, <span style="color:#66d9ef">nil</span>)
}
</code></pre></div><ul>
<li>避免通过GET方法、代码注释、自动填充、缓存等方式泄露敏感信息</li>
</ul>
<h4 id="153必须敏感数据存储">1.5.3【必须】敏感数据存储</h4>
<ul>
<li>敏感数据应使用SHA2、RSA等算法进行加密存储</li>
<li>敏感数据应使用独立的存储层，并在访问层开启访问控制</li>
<li>包含敏感信息的临时文件或缓存一旦不再需要应立刻删除</li>
</ul>
<h4 id="154必须异常处理和日志记录">1.5.4【必须】异常处理和日志记录</h4>
<ul>
<li>应合理使用panic、recover、defer处理系统异常，避免出错信息输出到前端</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">defer</span> <span style="color:#66d9ef">func</span> () {
        <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">r</span> <span style="color:#f92672">:=</span> recover(); <span style="color:#a6e22e">r</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
            <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Recovered in start()&#34;</span>)
        }
    }()
</code></pre></div><ul>
<li>对外环境禁止开启debug模式，或将程序运行日志输出到前端</li>
</ul>
<p>错误例子：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">dlv --listen<span style="color:#f92672">=</span>:2345 --headless<span style="color:#f92672">=</span>true --api-version<span style="color:#f92672">=</span><span style="color:#ae81ff">2</span> debug test.go
</code></pre></div><p>正确例子：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">dlv debug test.go
</code></pre></div><p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h3 id="16-加密解密">1.6 加密解密</h3>
<h4 id="161必须不得硬编码密码密钥">1.6.1【必须】不得硬编码密码/密钥</h4>
<ul>
<li>在进行用户登陆，加解密算法等操作时，不得在代码里硬编码密钥或密码，可通过变换算法或者配置等方式设置密码或者密钥。</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// bad
</span><span style="color:#75715e"></span><span style="color:#66d9ef">const</span> (
	<span style="color:#a6e22e">user</span>     = <span style="color:#e6db74">&#34;dbuser&#34;</span>
	<span style="color:#a6e22e">password</span> = <span style="color:#e6db74">&#34;s3cretp4ssword&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">connect</span>() <span style="color:#f92672">*</span><span style="color:#a6e22e">sql</span>.<span style="color:#a6e22e">DB</span> {
	<span style="color:#a6e22e">connStr</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;postgres://%s:%s@localhost/pqgotest&#34;</span>, <span style="color:#a6e22e">user</span>, <span style="color:#a6e22e">password</span>)
	<span style="color:#a6e22e">db</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">sql</span>.<span style="color:#a6e22e">Open</span>(<span style="color:#e6db74">&#34;postgres&#34;</span>, <span style="color:#a6e22e">connStr</span>)
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
	}
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">db</span>
}

<span style="color:#75715e">// bad
</span><span style="color:#75715e"></span><span style="color:#66d9ef">var</span> (
	<span style="color:#a6e22e">commonkey</span> = []byte(<span style="color:#e6db74">&#34;0123456789abcdef&#34;</span>)
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">AesEncrypt</span>(<span style="color:#a6e22e">plaintext</span> <span style="color:#66d9ef">string</span>) (<span style="color:#66d9ef">string</span>, <span style="color:#66d9ef">error</span>) {
	<span style="color:#a6e22e">block</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">aes</span>.<span style="color:#a6e22e">NewCipher</span>(<span style="color:#a6e22e">commonkey</span>)
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
		<span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;&#34;</span>, <span style="color:#a6e22e">err</span>
	}
}
</code></pre></div><h4 id="162必须密钥存储安全">1.6.2【必须】密钥存储安全</h4>
<ul>
<li>在使用对称密码算法时，需要保护好加密密钥。当算法涉及敏感、业务数据时，可通过非对称算法协商加密密钥。其他较为不敏感的数据加密，可以通过变换算法等方式保护密钥。</li>
</ul>
<h4 id="163推荐不使用弱密码算法">1.6.3【推荐】不使用弱密码算法</h4>
<ul>
<li>在使用加密算法时，不建议使用加密强度较弱的算法。</li>
</ul>
<p>错误例子：</p>
<pre><code>crypto/des，crypto/md5，crypto/sha1，crypto/rc4等。
</code></pre><p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h3 id="17-正则表达式">1.7 正则表达式</h3>
<h4 id="171推荐使用regexp进行正则表达式匹配">1.7.1【推荐】使用regexp进行正则表达式匹配</h4>
<ul>
<li>正则表达式编写不恰当可被用于DoS攻击，造成服务不可用，推荐使用regexp包进行正则表达式匹配。regexp保证了线性时间性能和优雅的失败：对解析器、编译器和执行引擎都进行了内存限制。但regexp不支持以下正则表达式特性，如业务依赖这些特性，则regexp不适合使用。
<ul>
<li>回溯引用<a href="https://www.regular-expressions.info/backref.html">Backreferences</a>和查看<a href="https://www.regular-expressions.info/lookaround.html">Lookaround</a></li>
</ul>
</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// good
</span><span style="color:#75715e"></span><span style="color:#a6e22e">matched</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">regexp</span>.<span style="color:#a6e22e">MatchString</span>(<span style="color:#e6db74">`a.b`</span>, <span style="color:#e6db74">&#34;aaxbb&#34;</span>)
<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">matched</span>) <span style="color:#75715e">// true
</span><span style="color:#75715e"></span><span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">err</span>)     <span style="color:#75715e">// nil (regexp is valid)
</span></code></pre></div><p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h1 id="后台类">后台类</h1>
<p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h2 id="1-代码实现类-1">1 代码实现类</h2>
<p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h3 id="11-输入校验">1.1 输入校验</h3>
<h4 id="111必须按类型进行数据校验">1.1.1【必须】按类型进行数据校验</h4>
<ul>
<li>所有外部输入的参数，应使用<code>validator</code>进行白名单校验，校验内容包括但不限于数据长度、数据范围、数据类型与格式，校验不通过的应当拒绝</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// good
</span><span style="color:#75715e"></span><span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;github.com/go-playground/validator/v10&#34;</span>
)

<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">validate</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">validator</span>.<span style="color:#a6e22e">Validate</span>
<span style="color:#a6e22e">validate</span> = <span style="color:#a6e22e">validator</span>.<span style="color:#a6e22e">New</span>()
<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">validateVariable</span>() {
	<span style="color:#a6e22e">myEmail</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;abc@tencent.com&#34;</span>
	<span style="color:#a6e22e">errs</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">validate</span>.<span style="color:#a6e22e">Var</span>(<span style="color:#a6e22e">myEmail</span>, <span style="color:#e6db74">&#34;required,email&#34;</span>)
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">errs</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">errs</span>)
		<span style="color:#66d9ef">return</span>
        <span style="color:#75715e">//停止执行
</span><span style="color:#75715e"></span>	}
	<span style="color:#75715e">// 验证通过，继续执行
</span><span style="color:#75715e"></span>    <span style="color:#f92672">...</span>
}
</code></pre></div><ul>
<li>无法通过白名单校验的应使用<code>html.EscapeString</code>、<code>text/template</code>或<code>bluemonday</code>对<code>&lt;, &gt;, &amp;, ',&quot;</code>等字符进行过滤或编码</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go">  <span style="color:#f92672">import</span>(
  	<span style="color:#e6db74">&#34;text/template&#34;</span>
  )
  
  <span style="color:#75715e">// TestHTMLEscapeString HTML特殊字符转义
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>(<span style="color:#a6e22e">inputValue</span> <span style="color:#66d9ef">string</span>) <span style="color:#66d9ef">string</span>{
  	<span style="color:#a6e22e">escapedResult</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">template</span>.<span style="color:#a6e22e">HTMLEscapeString</span>(<span style="color:#a6e22e">inputValue</span>)
  	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">escapedResult</span>
  }
</code></pre></div><p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h3 id="12-sql操作">1.2 SQL操作</h3>
<h4 id="121必须sql语句默认使用预编译并绑定变量">1.2.1【必须】SQL语句默认使用预编译并绑定变量</h4>
<ul>
<li>使用<code>database/sql</code>的prepare、Query或使用GORM等ORM执行SQL操作</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go">  <span style="color:#f92672">import</span> (
    <span style="color:#e6db74">&#34;github.com/jinzhu/gorm&#34;</span>
    <span style="color:#a6e22e">_</span> <span style="color:#e6db74">&#34;github.com/jinzhu/gorm/dialects/sqlite&#34;</span>
  )
  
  <span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Product</span> <span style="color:#66d9ef">struct</span> {
    <span style="color:#a6e22e">gorm</span>.<span style="color:#a6e22e">Model</span>
    <span style="color:#a6e22e">Code</span> <span style="color:#66d9ef">string</span>
    <span style="color:#a6e22e">Price</span> <span style="color:#66d9ef">uint</span>
  }
  <span style="color:#f92672">...</span>
  <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">product</span> <span style="color:#a6e22e">Product</span>
  <span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">First</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">product</span>, <span style="color:#ae81ff">1</span>)
</code></pre></div><ul>
<li>使用参数化查询，禁止拼接SQL语句，另外对于传入参数用于order by或表名的需要通过校验</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// bad
</span><span style="color:#75715e"></span>  <span style="color:#f92672">import</span> (
  	<span style="color:#e6db74">&#34;database/sql&#34;</span>
  	<span style="color:#e6db74">&#34;fmt&#34;</span>
  	<span style="color:#e6db74">&#34;net/http&#34;</span>
  )
  
  <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">handler</span>(<span style="color:#a6e22e">db</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">sql</span>.<span style="color:#a6e22e">DB</span>, <span style="color:#a6e22e">req</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) {
  	<span style="color:#a6e22e">q</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=&#39;%s&#39; ORDER BY PRICE&#34;</span>,
  		<span style="color:#a6e22e">req</span>.<span style="color:#a6e22e">URL</span>.<span style="color:#a6e22e">Query</span>()[<span style="color:#e6db74">&#34;category&#34;</span>])
  	<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Query</span>(<span style="color:#a6e22e">q</span>)
  }

<span style="color:#75715e">// good
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">handlerGood</span>(<span style="color:#a6e22e">db</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">sql</span>.<span style="color:#a6e22e">DB</span>, <span style="color:#a6e22e">req</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) {
    <span style="color:#75715e">//使用?占位符
</span><span style="color:#75715e"></span>  	<span style="color:#a6e22e">q</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=&#39;?&#39; ORDER BY PRICE&#34;</span>
  	<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Query</span>(<span style="color:#a6e22e">q</span>, <span style="color:#a6e22e">req</span>.<span style="color:#a6e22e">URL</span>.<span style="color:#a6e22e">Query</span>()[<span style="color:#e6db74">&#34;category&#34;</span>])
}
</code></pre></div><p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h3 id="13-网络请求">1.3 网络请求</h3>
<h4 id="131必须资源请求过滤验证">1.3.1【必须】资源请求过滤验证</h4>
<ul>
<li>
<p>使用<code>&quot;net/http&quot;</code>下的方法<code>http.Get(url)</code>、<code>http.Post(url, contentType, body)</code>、<code>http.Head(url )</code>、<code>http.PostForm(url, data)</code>、<code>http.Do(req)</code>时，如变量值外部可控(指从参数中动态获取)，应对请求目标进行严格的安全校验。</p>
</li>
<li>
<p>如请求资源域名归属固定的范围，如只允许<code>a.qq.com</code>和<code>b.qq.com</code>，应做白名单限制。如不适用白名单，则推荐的校验逻辑步骤是：</p>
<ul>
<li>
<p>第 1 步、只允许HTTP或HTTPS协议</p>
</li>
<li>
<p>第 2 步、解析目标URL，获取其HOST</p>
</li>
<li>
<p>第 3 步、解析HOST，获取HOST指向的IP地址转换成Long型</p>
</li>
<li>
<p>第 4 步、检查IP地址是否为内网IP，网段有：</p>
<pre><code>// 以RFC定义的专有网络为例，如有自定义私有网段亦应加入禁止访问列表。
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
127.0.0.0/8
</code></pre></li>
<li>
<p>第 5 步、请求URL</p>
</li>
<li>
<p>第 6 步、如有跳转，跳转后执行1，否则绑定经校验的ip和域名，对URL发起请求</p>
</li>
</ul>
</li>
<li>
<p>官方库<code>encoding/xml</code>不支持外部实体引用，使用该库可避免xxe漏洞</p>
</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go">  <span style="color:#f92672">import</span> (
  	<span style="color:#e6db74">&#34;encoding/xml&#34;</span>
  	<span style="color:#e6db74">&#34;fmt&#34;</span>
      <span style="color:#e6db74">&#34;os&#34;</span>
  )
  
  <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
  	<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Person</span> <span style="color:#66d9ef">struct</span> {
  		<span style="color:#a6e22e">XMLName</span>   <span style="color:#a6e22e">xml</span>.<span style="color:#a6e22e">Name</span> <span style="color:#e6db74">`xml:&#34;person&#34;`</span>
  		<span style="color:#a6e22e">Id</span>        <span style="color:#66d9ef">int</span>      <span style="color:#e6db74">`xml:&#34;id,attr&#34;`</span>
  		<span style="color:#a6e22e">UserName</span> <span style="color:#66d9ef">string</span>   <span style="color:#e6db74">`xml:&#34;name&gt;first&#34;`</span>
  		<span style="color:#a6e22e">Comment</span> <span style="color:#66d9ef">string</span> <span style="color:#e6db74">`xml:&#34;,comment&#34;`</span>
  	}
  
  	<span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">Person</span>{<span style="color:#a6e22e">Id</span>: <span style="color:#ae81ff">13</span>, <span style="color:#a6e22e">UserName</span>: <span style="color:#e6db74">&#34;John&#34;</span>}
  	<span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">Comment</span> = <span style="color:#e6db74">&#34; Need more details. &#34;</span>
  
  	<span style="color:#a6e22e">enc</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">xml</span>.<span style="color:#a6e22e">NewEncoder</span>(<span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Stdout</span>)
  	<span style="color:#a6e22e">enc</span>.<span style="color:#a6e22e">Indent</span>(<span style="color:#e6db74">&#34;  &#34;</span>, <span style="color:#e6db74">&#34;    &#34;</span>)
  	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">enc</span>.<span style="color:#a6e22e">Encode</span>(<span style="color:#a6e22e">v</span>); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
  		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;error: %v\n&#34;</span>, <span style="color:#a6e22e">err</span>)
  	}
  
  }
</code></pre></div><p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h3 id="14-服务器端渲染">1.4 服务器端渲染</h3>
<h4 id="141必须模板渲染过滤验证">1.4.1【必须】模板渲染过滤验证</h4>
<ul>
<li>使用<code>text/template</code>或者<code>html/template</code>渲染模板时禁止将外部输入参数引入模板，或仅允许引入白名单内字符。</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go">   <span style="color:#75715e">// bad
</span><span style="color:#75715e"></span>    <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">handler</span>(<span style="color:#a6e22e">w</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ResponseWriter</span>, <span style="color:#a6e22e">r</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) {
      <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">ParseForm</span>()
      <span style="color:#a6e22e">x</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">Form</span>.<span style="color:#a6e22e">Get</span>(<span style="color:#e6db74">&#34;name&#34;</span>)
     
      <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">tmpl</span> = <span style="color:#e6db74">`&lt;!DOCTYPE html&gt;&lt;html&gt;&lt;body&gt;
</span><span style="color:#e6db74">    &lt;form action=&#34;/&#34; method=&#34;post&#34;&gt;
</span><span style="color:#e6db74">        First name:&lt;br&gt;
</span><span style="color:#e6db74">    &lt;input type=&#34;text&#34; name=&#34;name&#34; value=&#34;&#34;&gt;
</span><span style="color:#e6db74">    &lt;input type=&#34;submit&#34; value=&#34;Submit&#34;&gt;
</span><span style="color:#e6db74">    &lt;/form&gt;&lt;p&gt;`</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">x</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">` &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;`</span>
    
      <span style="color:#a6e22e">t</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">template</span>.<span style="color:#a6e22e">New</span>(<span style="color:#e6db74">&#34;main&#34;</span>)
      <span style="color:#a6e22e">t</span>, <span style="color:#a6e22e">_</span> = <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Parse</span>(<span style="color:#a6e22e">tmpl</span>)
      <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Execute</span>(<span style="color:#a6e22e">w</span>, <span style="color:#e6db74">&#34;Hello&#34;</span>)
    }

<span style="color:#75715e">// good
</span><span style="color:#75715e"></span>    <span style="color:#f92672">import</span> (
    	<span style="color:#e6db74">&#34;fmt&#34;</span>
    	<span style="color:#e6db74">&#34;github.com/go-playground/validator/v10&#34;</span>
    )

    <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">validate</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">validator</span>.<span style="color:#a6e22e">Validate</span>
    <span style="color:#a6e22e">validate</span> = <span style="color:#a6e22e">validator</span>.<span style="color:#a6e22e">New</span>()
    <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">validateVariable</span>(<span style="color:#a6e22e">val</span>) {
    	<span style="color:#a6e22e">errs</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">validate</span>.<span style="color:#a6e22e">Var</span>(<span style="color:#a6e22e">val</span>, <span style="color:#e6db74">&#34;gte=1,lte=100&#34;</span>)<span style="color:#75715e">//限制必须是1-100的正整数
</span><span style="color:#75715e"></span>    	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">errs</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
    		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">errs</span>)
    		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">False</span>
    	}
        <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">True</span>
    }
    
    <span style="color:#66d9ef">func</span> <span style="color:#a6e22e">handler</span>(<span style="color:#a6e22e">w</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ResponseWriter</span>, <span style="color:#a6e22e">r</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) {
        <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">ParseForm</span>()
        <span style="color:#a6e22e">x</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">Form</span>.<span style="color:#a6e22e">Get</span>(<span style="color:#e6db74">&#34;name&#34;</span>)
    
        <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">validateVariable</span>(<span style="color:#a6e22e">x</span>):
            <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">tmpl</span> = <span style="color:#e6db74">`&lt;!DOCTYPE html&gt;&lt;html&gt;&lt;body&gt;
</span><span style="color:#e6db74">            &lt;form action=&#34;/&#34; method=&#34;post&#34;&gt;
</span><span style="color:#e6db74">            First name:&lt;br&gt;
</span><span style="color:#e6db74">            &lt;input type=&#34;text&#34; name=&#34;name&#34; value=&#34;&#34;&gt;
</span><span style="color:#e6db74">            &lt;input type=&#34;submit&#34; value=&#34;Submit&#34;&gt;
</span><span style="color:#e6db74">            &lt;/form&gt;&lt;p&gt;`</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">x</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">` &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;`</span>
            <span style="color:#a6e22e">t</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">template</span>.<span style="color:#a6e22e">New</span>(<span style="color:#e6db74">&#34;main&#34;</span>)
            <span style="color:#a6e22e">t</span>, <span style="color:#a6e22e">_</span> = <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Parse</span>(<span style="color:#a6e22e">tmpl</span>)
            <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Execute</span>(<span style="color:#a6e22e">w</span>, <span style="color:#e6db74">&#34;Hello&#34;</span>)
        <span style="color:#66d9ef">else</span>:
            <span style="color:#f92672">...</span>
    }
    
</code></pre></div><p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h3 id="15-web跨域">1.5 Web跨域</h3>
<h4 id="151必须跨域资源共享cors限制请求来源">1.5.1【必须】跨域资源共享CORS限制请求来源</h4>
<ul>
<li>CORS请求保护不当可导致敏感信息泄漏，因此应当严格设置Access-Control-Allow-Origin使用同源策略进行保护。</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"> <span style="color:#75715e">// good
</span><span style="color:#75715e"></span>  <span style="color:#a6e22e">c</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cors</span>.<span style="color:#a6e22e">New</span>(<span style="color:#a6e22e">cors</span>.<span style="color:#a6e22e">Options</span>{
      <span style="color:#a6e22e">AllowedOrigins</span>: []<span style="color:#66d9ef">string</span>{<span style="color:#e6db74">&#34;http://qq.com&#34;</span>, <span style="color:#e6db74">&#34;https://qq.com&#34;</span>},
      <span style="color:#a6e22e">AllowCredentials</span>: <span style="color:#66d9ef">true</span>,
      <span style="color:#a6e22e">Debug</span>: <span style="color:#66d9ef">false</span>,
  })
  
  <span style="color:#75715e">//引入中间件
</span><span style="color:#75715e"></span>  <span style="color:#a6e22e">handler</span> = <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Handler</span>(<span style="color:#a6e22e">handler</span>)
</code></pre></div><p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h3 id="16-响应输出">1.6 响应输出</h3>
<h4 id="161-必须设置正确的http响应包类型">1.6.1 【必须】设置正确的HTTP响应包类型</h4>
<ul>
<li>响应头Content-Type与实际响应内容，应保持一致。如：API响应数据类型是json，则响应头使用<code>application/json</code>；若为xml，则设置为<code>text/xml</code>。</li>
</ul>
<h4 id="162-必须添加安全响应头">1.6.2 【必须】添加安全响应头</h4>
<ul>
<li>所有接口、页面，添加响应头 <code>X-Content-Type-Options: nosniff</code>。</li>
<li>所有接口、页面，添加响应头<code>X-Frame-Options </code>。按需合理设置其允许范围，包括：<code>DENY</code>、<code>SAMEORIGIN</code>、<code>ALLOW-FROM origin</code>。用法参考：<a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/X-Frame-Options">MDN文档</a></li>
</ul>
<h4 id="163必须外部输入拼接到http响应头中需进行过滤">1.6.3【必须】外部输入拼接到HTTP响应头中需进行过滤</h4>
<ul>
<li>应尽量避免外部可控参数拼接到HTTP响应头中，如业务需要则需要过滤掉<code>\r</code>、<code>\n</code>等换行符，或者拒绝携带换行符号的外部输入。</li>
</ul>
<h4 id="164必须外部输入拼接到response页面前进行编码处理">1.6.4【必须】外部输入拼接到response页面前进行编码处理</h4>
<ul>
<li>直出html页面或使用模板生成html页面的，推荐使用<code>text/template</code>自动编码，或者使用<code>html.EscapeString</code>或<code>text/template</code>对<code>&lt;, &gt;, &amp;, ',&quot;</code>等字符进行编码。</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">import</span>(
	<span style="color:#e6db74">&#34;html/template&#34;</span>
)        

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">outtemplate</span>(<span style="color:#a6e22e">w</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ResponseWriter</span>,<span style="color:#a6e22e">r</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) {
    <span style="color:#a6e22e">param1</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">URL</span>.<span style="color:#a6e22e">Query</span>().<span style="color:#a6e22e">Get</span>(<span style="color:#e6db74">&#34;param1&#34;</span>)
    <span style="color:#a6e22e">tmpl</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">template</span>.<span style="color:#a6e22e">New</span>(<span style="color:#e6db74">&#34;hello&#34;</span>)
    <span style="color:#a6e22e">tmpl</span>, <span style="color:#a6e22e">_</span> = <span style="color:#a6e22e">tmpl</span>.<span style="color:#a6e22e">Parse</span>(<span style="color:#e6db74">`</span><span style="color:#75715e">{{</span><span style="color:#a6e22e">define</span> <span style="color:#e6db74">&#34;T&#34;</span><span style="color:#75715e">}}{{</span><span style="color:#a6e22e">.</span><span style="color:#75715e">}}{{</span><span style="color:#66d9ef">end</span><span style="color:#75715e">}}</span><span style="color:#e6db74">`</span>)
    <span style="color:#a6e22e">tmpl</span>.<span style="color:#a6e22e">ExecuteTemplate</span>(<span style="color:#a6e22e">w</span>, <span style="color:#e6db74">&#34;T&#34;</span>, <span style="color:#a6e22e">param1</span>)
}
</code></pre></div><p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h3 id="17-会话管理">1.7 会话管理</h3>
<h4 id="171必须安全维护session信息">1.7.1【必须】安全维护session信息</h4>
<ul>
<li>用户登录时应重新生成session，退出登录后应清理session。</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;net/http&#34;</span>
	<span style="color:#e6db74">&#34;github.com/gorilla/mux&#34;</span>
	<span style="color:#e6db74">&#34;github.com/gorilla/handlers&#34;</span>
)

<span style="color:#75715e">//创建cookie
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">setToken</span>(<span style="color:#a6e22e">res</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ResponseWriter</span>, <span style="color:#a6e22e">req</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) {
    <span style="color:#a6e22e">expireToken</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>().<span style="color:#a6e22e">Add</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Minute</span> <span style="color:#f92672">*</span> <span style="color:#ae81ff">30</span>).<span style="color:#a6e22e">Unix</span>()
    <span style="color:#a6e22e">expireCookie</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>().<span style="color:#a6e22e">Add</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Minute</span> <span style="color:#f92672">*</span> <span style="color:#ae81ff">30</span>)
    <span style="color:#f92672">...</span>
    <span style="color:#a6e22e">cookie</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Cookie</span>{
        <span style="color:#a6e22e">Name</span>: <span style="color:#e6db74">&#34;Auth&#34;</span>,
        <span style="color:#a6e22e">Value</span>: <span style="color:#a6e22e">signedToken</span>,
        <span style="color:#a6e22e">Expires</span>: <span style="color:#a6e22e">expireCookie</span>, <span style="color:#75715e">// 过期失效
</span><span style="color:#75715e"></span>        <span style="color:#a6e22e">HttpOnly</span>: <span style="color:#66d9ef">true</span>,
        <span style="color:#a6e22e">Path</span>: <span style="color:#e6db74">&#34;/&#34;</span>,
        <span style="color:#a6e22e">Domain</span>: <span style="color:#e6db74">&#34;127.0.0.1&#34;</span>,
        <span style="color:#a6e22e">Secure</span>: <span style="color:#66d9ef">true</span>
    }

    <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">SetCookie</span>(<span style="color:#a6e22e">res</span>, <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">cookie</span>)
    <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Redirect</span>(<span style="color:#a6e22e">res</span>, <span style="color:#a6e22e">req</span>, <span style="color:#e6db74">&#34;/profile&#34;</span>, <span style="color:#ae81ff">307</span>)
}
<span style="color:#75715e">// 删除cookie
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">logout</span>(<span style="color:#a6e22e">res</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ResponseWriter</span>, <span style="color:#a6e22e">req</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) {
    <span style="color:#a6e22e">deleteCookie</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Cookie</span>{
        <span style="color:#a6e22e">Name</span>: <span style="color:#e6db74">&#34;Auth&#34;</span>,
        <span style="color:#a6e22e">Value</span>: <span style="color:#e6db74">&#34;none&#34;</span>,
        <span style="color:#a6e22e">Expires</span>: <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>()
    }
    <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">SetCookie</span>(<span style="color:#a6e22e">res</span>, <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">deleteCookie</span>)
    <span style="color:#66d9ef">return</span>
}
</code></pre></div><h4 id="172必须csrf防护">1.7.2【必须】CSRF防护</h4>
<ul>
<li>涉及系统敏感操作或可读取敏感信息的接口应校验<code>Referer</code>或添加<code>csrf_token</code>。</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// good
</span><span style="color:#75715e"></span><span style="color:#f92672">import</span> (
    <span style="color:#e6db74">&#34;net/http&#34;</span>
    <span style="color:#e6db74">&#34;github.com/gorilla/csrf&#34;</span>
    <span style="color:#e6db74">&#34;github.com/gorilla/mux&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
    <span style="color:#a6e22e">r</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">mux</span>.<span style="color:#a6e22e">NewRouter</span>()
    <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">HandleFunc</span>(<span style="color:#e6db74">&#34;/signup&#34;</span>, <span style="color:#a6e22e">ShowSignupForm</span>)
    <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">HandleFunc</span>(<span style="color:#e6db74">&#34;/signup/post&#34;</span>, <span style="color:#a6e22e">SubmitSignupForm</span>)
    <span style="color:#75715e">//使用csrf_token验证
</span><span style="color:#75715e"></span>    <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ListenAndServe</span>(<span style="color:#e6db74">&#34;:8000&#34;</span>,
        <span style="color:#a6e22e">csrf</span>.<span style="color:#a6e22e">Protect</span>([]byte(<span style="color:#e6db74">&#34;32-byte-long-auth-key&#34;</span>))(<span style="color:#a6e22e">r</span>))
}
</code></pre></div><p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h3 id="18-访问控制">1.8 访问控制</h3>
<h4 id="181必须默认鉴权">1.8.1【必须】默认鉴权</h4>
<ul>
<li>
<p>除非资源完全可对外开放，否则系统默认进行身份认证，使用白名单的方式放开不需要认证的接口或页面。</p>
</li>
<li>
<p>根据资源的机密程度和用户角色，以最小权限原则，设置不同级别的权限，如完全公开、登录可读、登录可写、特定用户可读、特定用户可写等</p>
</li>
<li>
<p>涉及用户自身相关的数据的读写必须验证登录态用户身份及其权限，避免越权操作</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sql" data-lang="sql"><span style="color:#75715e">-- 伪代码
</span><span style="color:#75715e"></span><span style="color:#66d9ef">select</span> id <span style="color:#66d9ef">from</span> <span style="color:#66d9ef">table</span> <span style="color:#66d9ef">where</span> id<span style="color:#f92672">=</span>:id <span style="color:#66d9ef">and</span> userid<span style="color:#f92672">=</span><span style="color:#66d9ef">session</span>.userid
</code></pre></div></li>
<li>
<p>没有独立账号体系的外网服务使用<code>QQ</code>或<code>微信</code>登录，内网服务使用<code>统一登录服务</code>登录，其他使用账号密码登录的服务需要增加验证码等二次验证</p>
</li>
</ul>
<p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h3 id="19-并发保护">1.9 并发保护</h3>
<h4 id="191必须禁止在闭包中直接调用循环变量">1.9.1【必须】禁止在闭包中直接调用循环变量</h4>
<ul>
<li>在循环中启动协程，当协程中使用到了循环的索引值，由于多个协程同时使用同一个变量会产生数据竞争，造成执行结果异常。</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// bad
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
    <span style="color:#a6e22e">runtime</span>.<span style="color:#a6e22e">GOMAXPROCS</span>(<span style="color:#a6e22e">runtime</span>.<span style="color:#a6e22e">NumCPU</span>())
    <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">group</span> <span style="color:#a6e22e">sync</span>.<span style="color:#a6e22e">WaitGroup</span>

    <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; <span style="color:#ae81ff">5</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> {
        <span style="color:#a6e22e">group</span>.<span style="color:#a6e22e">Add</span>(<span style="color:#ae81ff">1</span>)
        <span style="color:#66d9ef">go</span> <span style="color:#66d9ef">func</span>() {
            <span style="color:#66d9ef">defer</span> <span style="color:#a6e22e">group</span>.<span style="color:#a6e22e">Done</span>()
            <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;%-2d&#34;</span>, <span style="color:#a6e22e">i</span>) <span style="color:#75715e">//这里打印的i不是所期望的
</span><span style="color:#75715e"></span>        }()
    }
    <span style="color:#a6e22e">group</span>.<span style="color:#a6e22e">Wait</span>()
}

<span style="color:#75715e">// good
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
    <span style="color:#a6e22e">runtime</span>.<span style="color:#a6e22e">GOMAXPROCS</span>(<span style="color:#a6e22e">runtime</span>.<span style="color:#a6e22e">NumCPU</span>())
    <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">group</span> <span style="color:#a6e22e">sync</span>.<span style="color:#a6e22e">WaitGroup</span>

    <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; <span style="color:#ae81ff">5</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> {
        <span style="color:#a6e22e">group</span>.<span style="color:#a6e22e">Add</span>(<span style="color:#ae81ff">1</span>)
        <span style="color:#66d9ef">go</span> <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">j</span> <span style="color:#66d9ef">int</span>) {
            <span style="color:#66d9ef">defer</span> <span style="color:#66d9ef">func</span>() {
                <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">r</span> <span style="color:#f92672">:=</span> recover(); <span style="color:#a6e22e">r</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
                    <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;Recovered in start()&#34;</span>)
                }
                <span style="color:#a6e22e">group</span>.<span style="color:#a6e22e">Done</span>()
            }()
        <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;%-2d&#34;</span>, <span style="color:#a6e22e">j</span>) <span style="color:#75715e">// 闭包内部使用局部变量
</span><span style="color:#75715e"></span>        }(<span style="color:#a6e22e">i</span>)  <span style="color:#75715e">// 把循环变量显式地传给协程
</span><span style="color:#75715e"></span>    }
    <span style="color:#a6e22e">group</span>.<span style="color:#a6e22e">Wait</span>()
}
</code></pre></div><h4 id="192必须禁止并发写map">1.9.2【必须】禁止并发写map</h4>
<ul>
<li>并发写map容易造成程序崩溃并异常退出，建议加锁保护</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// bad
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">m</span> <span style="color:#f92672">:=</span> make(<span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">int</span>]<span style="color:#66d9ef">int</span>)
	<span style="color:#75715e">//并发读写
</span><span style="color:#75715e"></span>	<span style="color:#66d9ef">go</span> <span style="color:#66d9ef">func</span>() {
		<span style="color:#66d9ef">for</span> {
			<span style="color:#a6e22e">_</span> = <span style="color:#a6e22e">m</span>[<span style="color:#ae81ff">1</span>] 
		}
	}()
	<span style="color:#66d9ef">go</span> <span style="color:#66d9ef">func</span>() {
		<span style="color:#66d9ef">for</span> {
			<span style="color:#a6e22e">m</span>[<span style="color:#ae81ff">2</span>] = <span style="color:#ae81ff">1</span>
		}
	}()
	<span style="color:#66d9ef">select</span> {}
}
</code></pre></div><h4 id="193必须确保并发安全">1.9.3【必须】确保并发安全</h4>
<p>敏感操作如果未作并发安全限制，可导致数据读写异常，造成业务逻辑限制被绕过。可通过同步锁或者原子操作进行防护。</p>
<p>通过同步锁共享内存</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// good
</span><span style="color:#75715e"></span><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">count</span> <span style="color:#66d9ef">int</span>
<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">Count</span>(<span style="color:#a6e22e">lock</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">sync</span>.<span style="color:#a6e22e">Mutex</span>) {
    <span style="color:#a6e22e">lock</span>.<span style="color:#a6e22e">Lock</span>()<span style="color:#75715e">// 加写锁
</span><span style="color:#75715e"></span>    <span style="color:#a6e22e">count</span><span style="color:#f92672">++</span>
    <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">count</span>)
    <span style="color:#a6e22e">lock</span>.<span style="color:#a6e22e">Unlock</span>()<span style="color:#75715e">// 解写锁，任何一个Lock()或RLock()均需要保证对应有Unlock()或RUnlock()
</span><span style="color:#75715e"></span>}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
    <span style="color:#a6e22e">lock</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">sync</span>.<span style="color:#a6e22e">Mutex</span>{}
    <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; <span style="color:#ae81ff">10</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> {
        <span style="color:#66d9ef">go</span> <span style="color:#a6e22e">Count</span>(<span style="color:#a6e22e">lock</span>) <span style="color:#75715e">//传递指针是为了防止函数内的锁和调用锁不一致
</span><span style="color:#75715e"></span>    }
    <span style="color:#66d9ef">for</span> {
        <span style="color:#a6e22e">lock</span>.<span style="color:#a6e22e">Lock</span>()
        <span style="color:#a6e22e">c</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">count</span>
        <span style="color:#a6e22e">lock</span>.<span style="color:#a6e22e">Unlock</span>()
        <span style="color:#a6e22e">runtime</span>.<span style="color:#a6e22e">Gosched</span>()<span style="color:#75715e">//交出时间片给协程
</span><span style="color:#75715e"></span>        <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">c</span> &gt; <span style="color:#ae81ff">10</span> {
            <span style="color:#66d9ef">break</span>
        }
    }
}
</code></pre></div><ul>
<li>使用<code>sync/atomic</code>执行原子操作</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// good
</span><span style="color:#75715e"></span><span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;sync&#34;</span>
	<span style="color:#e6db74">&#34;sync/atomic&#34;</span>
)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Map</span> <span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#66d9ef">string</span>
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">m</span> <span style="color:#a6e22e">atomic</span>.<span style="color:#a6e22e">Value</span>
	<span style="color:#a6e22e">m</span>.<span style="color:#a6e22e">Store</span>(make(<span style="color:#a6e22e">Map</span>))
	<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">mu</span> <span style="color:#a6e22e">sync</span>.<span style="color:#a6e22e">Mutex</span> <span style="color:#75715e">// used only by writers
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">read</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">key</span> <span style="color:#66d9ef">string</span>) (<span style="color:#a6e22e">val</span> <span style="color:#66d9ef">string</span>) {
		<span style="color:#a6e22e">m1</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">m</span>.<span style="color:#a6e22e">Load</span>().(<span style="color:#a6e22e">Map</span>)
		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">m1</span>[<span style="color:#a6e22e">key</span>]
	}
	<span style="color:#a6e22e">insert</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">key</span>, <span style="color:#a6e22e">val</span> <span style="color:#66d9ef">string</span>) {
		<span style="color:#a6e22e">mu</span>.<span style="color:#a6e22e">Lock</span>() <span style="color:#75715e">// 与潜在写入同步
</span><span style="color:#75715e"></span>		<span style="color:#66d9ef">defer</span> <span style="color:#a6e22e">mu</span>.<span style="color:#a6e22e">Unlock</span>()
		<span style="color:#a6e22e">m1</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">m</span>.<span style="color:#a6e22e">Load</span>().(<span style="color:#a6e22e">Map</span>) <span style="color:#75715e">// 导入struct当前数据
</span><span style="color:#75715e"></span>		<span style="color:#a6e22e">m2</span> <span style="color:#f92672">:=</span> make(<span style="color:#a6e22e">Map</span>)      <span style="color:#75715e">// 创建新值
</span><span style="color:#75715e"></span>		<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">k</span>, <span style="color:#a6e22e">v</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">m1</span> {
			<span style="color:#a6e22e">m2</span>[<span style="color:#a6e22e">k</span>] = <span style="color:#a6e22e">v</span>
		}
		<span style="color:#a6e22e">m2</span>[<span style="color:#a6e22e">key</span>] = <span style="color:#a6e22e">val</span>
		<span style="color:#a6e22e">m</span>.<span style="color:#a6e22e">Store</span>(<span style="color:#a6e22e">m2</span>)   <span style="color:#75715e">// 用新的替代当前对象
</span><span style="color:#75715e"></span>	}
	<span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">_</span> = <span style="color:#a6e22e">read</span>, <span style="color:#a6e22e">insert</span>
}
</code></pre></div>
        </div>

        
<div class="post-archive">
    <ul class="post-copyright">
        <li><strong>原文作者：</strong><a rel="author" href="https://luckly.work/">luckly</a></li>
        <li style="word-break:break-all"><strong>原文链接：</strong><a href="https://luckly.work/post/go/Go%E5%AE%89%E5%85%A8%E6%8C%87%E5%8D%97/">https://luckly.work/post/go/Go%E5%AE%89%E5%85%A8%E6%8C%87%E5%8D%97/</a></li>
        <li><strong>版权声明：</strong>本作品采用<a rel="license" href="https://creativecommons.org/licenses/by-nc-nd/4.0/">知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议</a>进行许可，非商业转载请注明出处（作者，原文链接），商业转载请联系作者获得授权。</li>
    </ul>
</div>
<br/>



        

<div class="post-archive">
    <h2>See Also</h2>
    <ul class="listing">
        
        <li><a href="/post/Flutter/Flutter%E7%9B%AE%E5%BD%95/">《Flutter目录》</a></li>
        
        <li><a href="/post/Flutter/%E5%9C%A8Flutter%E4%B8%AD%E5%88%B6%E4%BD%9CWhatsappcloneapp%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F/">《在Flutter中制作Whatsappcloneapp应用程序》</a></li>
        
        <li><a href="/post/Flutter/%E5%9C%A8Flutter%E4%B8%AD%E5%88%B6%E4%BD%9CGlassmorphism%E6%95%88%E6%9E%9C%E4%BE%A7%E8%BE%B9%E6%A0%8F%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F/">《在Flutter中制作Glassmorphism效果侧边栏应用程序》</a></li>
        
        <li><a href="/post/Flutter/Flutter%E7%94%B5%E5%AD%90%E4%B9%A604/">《Flutter电子书04》</a></li>
        
        <li><a href="/post/Flutter/%E5%9C%A8Flutter%E4%B8%AD%E5%88%B6%E4%BD%9C%E8%B6%B3%E7%90%83%E8%AE%B0%E5%88%86%E7%89%8C%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F/">《在Flutter中制作足球记分牌应用程序》</a></li>
        
    </ul>
</div>


        <div class="post-meta meta-tags">
            
            <ul class="clearfix">
                
                <li><a href='/tags/go'>go</a></li>
                
            </ul>
            
        </div>
    </article>
    
    

    
    
    <div class="post bg-white">
      <script src="https://utteranc.es/client.js"
            repo= "https://github.com/ITmxs/repo"
            issue-term="pathname"
            theme="github-light"
            crossorigin="anonymous"
            async>
      </script>
    </div>
    
</div>

                    <footer id="footer">
    <div>
        &copy; 2021 <a href="https://luckly.work/">早起的年轻人 By luckly</a>
        
        | <a rel="nofollow" target="_blank" href="http://beian.miit.gov.cn/">粤ICP备2021号-1</a>
        
    </div>
    <br />
    <div>
        <div class="github-badge">
            <a href="https://juejin.cn/user/3843548384077192" target="_black" rel="nofollow"><span class="badge-subject">Powered by</span><span class="badge-value bg-blue">掘金</span></a>
        </div>
        <div class="github-badge">
            <a href="https://space.bilibili.com/480883651" target="_black"><span class="badge-subject">Design by</span><span class="badge-value bg-brightgreen">早起的年轻人</span></a>
        </div>
        <div class="github-badge">
            <a href="https://cloud.tencent.com/developer/user/6702670" target="_black"><span class="badge-subject">Theme</span><span class="badge-value bg-yellowgreen">云社区</span></a>
        </div>
    </div>
</footer>


    
    <script type="text/javascript">
        window.MathJax = {
            tex2jax: {
                inlineMath: [['$', '$']],
                processEscapes: true
                }
            };
    </script>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML' async></script><script src="https://cdn.bootcdn.net/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.js"></script>

<a id="rocket" href="#top"></a>
<script type="text/javascript" src='/js/totop.js?v=0.0.0' async=""></script>



    <script type="text/javascript" src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" async></script>




    <script src='/js/douban.js'></script>
    <script src="/js/copy-to-clipboard.js"></script>

                </div>

                <div id="secondary">
    <section class="widget">
        <form id="search" action='https://luckly.work/search/' method="get" accept-charset="utf-8" target="_blank" _lpchecked="1">
      
      <input type="text" name="q" maxlength="20" placeholder="Search">
      <input type="hidden" name="sitesearch" value="https://luckly.work/">
      <button type="submit" class="submit icon-search"></button>
</form>
    </section>
    
    <section class="widget">
        <h3 class="widget-title">最近文章</h3>
<ul class="widget-list">
    
    <li>
        <a href="https://luckly.work/post/nginx/nginx%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9/" title="Nginx文件内容">Nginx文件内容</a>
    </li>
    
    <li>
        <a href="https://luckly.work/post/nginx/nginx%E6%9E%81%E7%AE%80%E6%95%99%E7%A8%8B/" title="Nginx极简教程">Nginx极简教程</a>
    </li>
    
    <li>
        <a href="https://luckly.work/post/nginx/%E5%8D%81%E5%88%86%E9%92%9F%E5%85%A5%E9%97%A8nginx/" title="十分钟入门Nginx">十分钟入门Nginx</a>
    </li>
    
    <li>
        <a href="https://luckly.work/post/go/Goland%E8%BF%9C%E7%A8%8B%E5%BC%80%E5%8F%91%E9%85%8D%E7%BD%AE/" title="Goland远程开发配置">Goland远程开发配置</a>
    </li>
    
    <li>
        <a href="https://luckly.work/post/%E8%AF%BB%E4%B9%A6/%E5%9F%9F%E5%90%8D%E8%A7%A3%E6%9E%90/" title="域名解析">域名解析</a>
    </li>
    
    <li>
        <a href="https://luckly.work/post/git/%E6%8F%90%E4%BA%A4%E8%BF%87%E7%A8%8B%E7%9C%81%E7%95%A5%E6%9F%90%E4%BA%9B%E6%96%87%E4%BB%B6/" title="提交过程省略某些文件">提交过程省略某些文件</a>
    </li>
    
    <li>
        <a href="https://luckly.work/post/flutter_tips/Flutter_DropdownButton%E7%A4%BA%E4%BE%8B/" title="Flutter_DropdownButton示例">Flutter_DropdownButton示例</a>
    </li>
    
    <li>
        <a href="https://luckly.work/post/flutter_tips/Flutter_ExpansionPanelList%E5%92%8CExpansionPanelList.radio%E7%A4%BA%E4%BE%8B/" title="Flutter_ExpansionPanelList和ExpansionPanelList">Flutter_ExpansionPanelList和ExpansionPanelList</a>
    </li>
    
    <li>
        <a href="https://luckly.work/post/flutter_tips/Flutter%E5%BE%AE%E4%BF%A1%E5%88%86%E4%BA%AB%E9%93%BE%E6%8E%A5%E8%B7%B3%E5%9B%9EApp%E6%8C%87%E5%AE%9A%E9%A1%B5%E9%9D%A2/" title="Flutter微信分享链接跳回App指定页面">Flutter微信分享链接跳回App指定页面</a>
    </li>
    
    <li>
        <a href="https://luckly.work/post/%E4%BF%A1%E6%81%AF%E7%B3%BB%E7%BB%9F/%E5%A4%96%E5%8C%85%E5%8F%AF%E8%83%BD%E7%9A%84%E9%97%AE%E9%A2%98/" title="外包可能的问题">外包可能的问题</a>
    </li>
    
</ul>
    </section>

    

    <section class="widget">
        <h3 class="widget-title"><a href='/categories/'>分类</a></h3>
<ul class="widget-list">
    
    <li><a href="https://luckly.work/categories/Flutter/">Flutter (326)</a></li>
    
    <li><a href="https://luckly.work/categories/IT/">IT (2)</a></li>
    
    <li><a href="https://luckly.work/categories/Kotlin/">Kotlin (2)</a></li>
    
    <li><a href="https://luckly.work/categories/Mysql/">Mysql (1)</a></li>
    
    <li><a href="https://luckly.work/categories/nginx/">nginx (1)</a></li>
    
    <li><a href="https://luckly.work/categories/Vue/">Vue (6)</a></li>
    
    <li><a href="https://luckly.work/categories/YouTube%E8%A7%86%E9%A2%91%E4%B8%8B%E8%BD%BD/">YouTube视频下载 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/android/">android (6)</a></li>
    
    <li><a href="https://luckly.work/categories/dart/">dart (96)</a></li>
    
    <li><a href="https://luckly.work/categories/Flutter/">Flutter (28)</a></li>
    
    <li><a href="https://luckly.work/categories/gin/">gin (25)</a></li>
    
    <li><a href="https://luckly.work/categories/git/">git (4)</a></li>
    
    <li><a href="https://luckly.work/categories/Go/">Go (102)</a></li>
    
    <li><a href="https://luckly.work/categories/gorm/">gorm (4)</a></li>
    
    <li><a href="https://luckly.work/categories/grpc/">grpc (1)</a></li>
    
    <li><a href="https://luckly.work/categories/html/">html (3)</a></li>
    
    <li><a href="https://luckly.work/categories/ios/">ios (1)</a></li>
    
    <li><a href="https://luckly.work/categories/linux/">linux (1)</a></li>
    
    <li><a href="https://luckly.work/categories/nginx/">nginx (6)</a></li>
    
    <li><a href="https://luckly.work/categories/python/">python (35)</a></li>
    
    <li><a href="https://luckly.work/categories/read/">读书笔记 (6)</a></li>
    
    <li><a href="https://luckly.work/categories/redis/">redis (2)</a></li>
    
    <li><a href="https://luckly.work/categories/%E4%B8%AA%E4%BA%BA%E8%B5%84%E6%96%99/">个人资料 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E4%B9%A6%E5%8D%95/">书单 (8)</a></li>
    
    <li><a href="https://luckly.work/categories/%E4%B9%A6%E8%AF%84/">书评 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E4%BF%A1%E6%81%AF%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86%E5%B8%88/">信息系统管理师 (19)</a></li>
    
    <li><a href="https://luckly.work/categories/%E4%BF%A1%E6%81%AF%E7%B3%BB%E7%BB%9F%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86%E5%B8%88/">信息系统项目管理师 (25)</a></li>
    
    <li><a href="https://luckly.work/categories/%E5%8E%9F%E5%88%99/">原则 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E5%8E%9F%E7%94%9F%E9%80%9A%E8%AE%AF/">原生通讯 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E5%9F%BA%E7%A1%80/">基础 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E5%A4%8D%E5%88%A9%E6%95%88%E5%BA%94/">复利效应 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/">安装教程 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E5%B0%91%E6%9C%89%E4%BA%BA%E8%B5%B0%E7%9A%84%E8%B7%AF/">少有人走的路 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E5%BF%83%E8%AF%AD/">心语 (3)</a></li>
    
    <li><a href="https://luckly.work/categories/%E6%8F%92%E4%BB%B6/">插件 (2)</a></li>
    
    <li><a href="https://luckly.work/categories/%E6%95%99%E5%AD%A6/">教学 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E7%8E%8B%E9%98%B3%E6%98%8E/">王阳明 (3)</a></li>
    
    <li><a href="https://luckly.work/categories/%E7%94%B5%E5%AD%90%E4%B9%A6/">电子书 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E7%99%BB%E9%99%86%E8%A1%A8%E5%8D%95/">登陆表单 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E7%A8%BB%E7%9B%9B%E5%92%8C%E5%A4%AB/">稻盛和夫 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E7%A9%B7%E7%88%B8%E7%88%B8%E5%AF%8C%E7%88%B8%E7%88%B8/">穷爸爸富爸爸 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E7%B2%BE%E8%BF%9B/">精进 (3)</a></li>
    
    <li><a href="https://luckly.work/categories/%E7%BC%96%E7%A8%8B/">编程 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E8%99%9A%E5%B9%BB/">虚幻 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E8%B4%A2%E5%8A%A1%E8%87%AA%E7%94%B1%E4%B9%8B%E8%B7%AF/">财务自由之路 (2)</a></li>
    
    <li><a href="https://luckly.work/categories/%E8%B7%91%E6%AD%A5/">跑步 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E8%B7%AF%E7%94%B1%E4%BC%A0%E5%8F%82/">路由传参 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E8%B7%AF%E7%BA%BF/">路线 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E8%BD%AF%E4%BB%B6%E5%AE%9E%E6%96%BD/">软件实施 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E9%98%B3%E6%98%8E%E5%BF%83%E5%AD%A6/">阳明心学 (3)</a></li>
    
    <li><a href="https://luckly.work/categories/%E9%A1%B9%E7%9B%AE/">项目 (1)</a></li>
    
    <li><a href="https://luckly.work/categories/%E9%AD%85%E5%8A%9B/">魅力 (1)</a></li>
    
</ul>
    </section>

    <section class="widget">
        <h3 class="widget-title"><a href='/tags/'>标签</a></h3>
<div class="tagcloud">
    
    <a href="https://luckly.work/tags/flutter/">flutter</a>
    
    <a href="https://luckly.work/tags/IT/">IT</a>
    
    <a href="https://luckly.work/tags/Kotlin/">Kotlin</a>
    
    <a href="https://luckly.work/tags/Mysql/">Mysql</a>
    
    <a href="https://luckly.work/tags/nginx/">nginx</a>
    
    <a href="https://luckly.work/tags/Vue/">Vue</a>
    
    <a href="https://luckly.work/tags/YouTube%E8%A7%86%E9%A2%91%E4%B8%8B%E8%BD%BD/">YouTube视频下载</a>
    
    <a href="https://luckly.work/tags/android/">android</a>
    
    <a href="https://luckly.work/tags/dart/">dart</a>
    
    <a href="https://luckly.work/tags/flutter/">flutter</a>
    
    <a href="https://luckly.work/tags/gin/">gin</a>
    
    <a href="https://luckly.work/tags/git/">git</a>
    
    <a href="https://luckly.work/tags/go/">go</a>
    
    <a href="https://luckly.work/tags/gorm/">gorm</a>
    
    <a href="https://luckly.work/tags/grpc/">grpc</a>
    
    <a href="https://luckly.work/tags/html/">html</a>
    
    <a href="https://luckly.work/tags/ios/">ios</a>
    
    <a href="https://luckly.work/tags/linux/">linux</a>
    
    <a href="https://luckly.work/tags/nginx/">nginx</a>
    
    <a href="https://luckly.work/tags/python/">python</a>
    
    <a href="https://luckly.work/tags/redis/">redis</a>
    
    <a href="https://luckly.work/tags/%E4%B8%AA%E4%BA%BA%E8%B5%84%E6%96%99/">个人资料</a>
    
    <a href="https://luckly.work/tags/%E4%B9%A6%E5%8D%95/">书单</a>
    
    <a href="https://luckly.work/tags/%E4%B9%A6%E8%AF%84/">书评</a>
    
    <a href="https://luckly.work/tags/%E4%BF%A1%E6%81%AF%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86%E5%B8%88/">信息系统管理师</a>
    
    <a href="https://luckly.work/tags/%E4%BF%A1%E6%81%AF%E7%B3%BB%E7%BB%9F%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86%E5%B8%88/">信息系统项目管理师</a>
    
    <a href="https://luckly.work/tags/%E5%85%A5%E9%97%A8/">入门</a>
    
    <a href="https://luckly.work/tags/%E5%8E%9F%E5%88%99/">原则</a>
    
    <a href="https://luckly.work/tags/%E5%8E%9F%E7%94%9F%E9%80%9A%E8%AE%AF/">原生通讯</a>
    
    <a href="https://luckly.work/tags/%E5%9F%BA%E7%A1%80/">基础</a>
    
    <a href="https://luckly.work/tags/%E5%A4%8D%E5%88%A9%E6%95%88%E5%BA%94/">复利效应</a>
    
    <a href="https://luckly.work/tags/%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/">安装教程</a>
    
    <a href="https://luckly.work/tags/%E5%B0%91%E6%9C%89%E4%BA%BA%E8%B5%B0%E7%9A%84%E8%B7%AF/">少有人走的路</a>
    
    <a href="https://luckly.work/tags/%E5%BF%83%E8%AF%AD/">心语</a>
    
    <a href="https://luckly.work/tags/%E6%8F%92%E4%BB%B6/">插件</a>
    
    <a href="https://luckly.work/tags/%E6%95%99%E5%AD%A6/">教学</a>
    
    <a href="https://luckly.work/tags/%E7%8E%8B%E9%98%B3%E6%98%8E/">王阳明</a>
    
    <a href="https://luckly.work/tags/%E7%94%B5%E5%AD%90%E4%B9%A6/">电子书</a>
    
    <a href="https://luckly.work/tags/%E7%99%BB%E9%99%86%E8%A1%A8%E5%8D%95/">登陆表单</a>
    
    <a href="https://luckly.work/tags/%E7%A8%BB%E7%9B%9B%E5%92%8C%E5%A4%AB/">稻盛和夫</a>
    
    <a href="https://luckly.work/tags/%E7%A9%B7%E7%88%B8%E7%88%B8%E5%AF%8C%E7%88%B8%E7%88%B8/">穷爸爸富爸爸</a>
    
    <a href="https://luckly.work/tags/%E7%B2%BE%E8%BF%9B/">精进</a>
    
    <a href="https://luckly.work/tags/%E7%BC%96%E7%A8%8B/">编程</a>
    
    <a href="https://luckly.work/tags/%E8%99%9A%E5%B9%BB/">虚幻</a>
    
    <a href="https://luckly.work/tags/%E8%AF%97/">诗</a>
    
    <a href="https://luckly.work/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/">读书笔记</a>
    
    <a href="https://luckly.work/tags/%E8%B4%A2%E5%8A%A1%E8%87%AA%E7%94%B1%E4%B9%8B%E8%B7%AF/">财务自由之路</a>
    
    <a href="https://luckly.work/tags/%E8%B7%91%E6%AD%A5/">跑步</a>
    
    <a href="https://luckly.work/tags/%E8%B7%AF%E7%94%B1%E4%BC%A0%E5%8F%82/">路由传参</a>
    
    <a href="https://luckly.work/tags/%E8%B7%AF%E7%BA%BF/">路线</a>
    
    <a href="https://luckly.work/tags/%E8%BD%AF%E4%BB%B6%E5%AE%9E%E6%96%BD/">软件实施</a>
    
    <a href="https://luckly.work/tags/%E9%80%9A%E8%AE%AF%E5%BD%95/">通讯录</a>
    
    <a href="https://luckly.work/tags/%E9%98%B3%E6%98%8E%E5%BF%83%E5%AD%A6/">阳明心学</a>
    
    <a href="https://luckly.work/tags/%E9%A1%B9%E7%9B%AE/">项目</a>
    
    <a href="https://luckly.work/tags/%E9%AD%85%E5%8A%9B/">魅力</a>
    
</div>
    </section>

    
<section class="widget">
    <h3 class="widget-title">友情链接</h3>
    <ul class="widget-list">
        
        <li>
            <a target="_blank" href="http://www.topgoer.com/" title="枯藤">枯藤</a>
        </li>
        
        <li>
            <a target="_blank" href="https://gorm.cn/zh_CN/docs/index.html" title="gorm">gorm</a>
        </li>
        
        <li>
            <a target="_blank" href="https://docs.python.org/zh-cn/3/tutorial/index.html" title="python">python</a>
        </li>
        
        <li>
            <a target="_blank" href="https://www.liwenzhou.com/" title="李文周">李文周的博客</a>
        </li>
        
        <li>
            <a target="_blank" href="http://www.xbzweb.com/" title="小包子的博客">小包子的博客</a>
        </li>
        
        <li>
            <a target="_blank" href="https://www.flysnow.org/" title="飞雪无情的博客">飞雪无情的博客</a>
        </li>
        
        <li>
            <a target="_blank" href="https://sliverhorn.com/" title="sliverhorn的博客">sliverhorn的博客</a>
        </li>
        
        <li>
            <a target="_blank" href="http://yuedu.baidu.com/ebook/14a722970740be1e640e9a3e" title="Android Gradle权威指南">Android Gradle权威指南</a>
        </li>
        
        <li>
            <a target="_blank" href="https://gesdh.cn/" title="小格子">格子导航</a>
        </li>
        
        <li>
            <a target="_blank" href="https://itachi.xyz/" title="阿林">itachi&#39;s Blog</a>
        </li>
        
        <li>
            <a target="_blank" href="https://darjun.github.io/" title="大俊">大俊Blog</a>
        </li>
        
        <li>
            <a target="_blank" href="https://geektutu.com/post/quick-golang.html" title="极客兔兔">极客兔兔Blog</a>
        </li>
        
        <li>
            <a target="_blank" href="http://zxfcumtcs.github.io/" title="赵雪峰">雪峰Blog</a>
        </li>
        
    </ul>
</section>


    <section class="widget">
        <h3 class="widget-title">其它</h3>
        <ul class="widget-list">
            <li><a href="https://luckly.work/index.xml">文章 RSS</a></li>
        </ul>
    </section>
</div>
            </div>
        </div>
    </div>
</body>

</html>